assume ds:data, cs:code, ss:stack data segment db 16 dup(0) data ends stack segment db 16 dup(0) stack ends code segment start: mov ax, data mov ds, ax mov ax, stack mov ss, ax mov sp, 16 mov ah, 4ch int 21h code ends end start
Initial Program State
- ES and DS registers both point to the segment containing the PSP structure.
- CS equals value specified in the header, relocated by adding the start segment address to it.
- IP equals value specified in the header. Note, that unlike in COM executables, MZ programs don't start at offset 0x100.
- SS equals value specified in the header, relocated, just like CS.
- SP equals value specified in the header.
- AL is 0x00 if the first FCB in the PSP has a valid drive identifier, 0xFF otherwise.
- AH is the same as AL, but for the second FCB in the PSP.
- All other registers may, or may not be set to 0. You should consider them undefined.
Controlling the Segment Order[1]
The assembler normally positions segments in the object file in the order in
which they appear in source code. The linker, in turn, processes object files inthe order in which they appear on the command line. Within each object file, the
linker outputs segments in the order they appear, subject to any group, class,
and .DOSSEG requirements.
assume ds:data, cs:code, ss:stack data segment db 4 dup(0) data ends stack segment db 8 dup(0) stack ends code segment start: mov ax, data mov ds, ax mov ax, stack mov ss, ax mov sp, 8 mov ah, 4ch int 21h code ends end start
在debug中将执行到line17结束、line19之前,记录此时:寄存器(DS) = 076C,寄存器(SS) = 076D,寄存器(CS) = 076E
假设程序加载后,code段的段地址是X,则,data段的段地址是X-2H, stack的段地址是 X-1H
assume ds:data, cs:code, ss:stack data segment db 20 dup(0) data ends stack segment db 20 dup(0) stack ends code segment start: mov ax, data mov ds, ax mov ax, stack mov ss, ax mov sp, 20 mov ah, 4ch int 21h code ends end start
在debug中将执行到line17结束、line19之前,记录此时:寄存器(DS) = 076C,寄存器(SS) = 076E,寄存器(CS) = 0770
假设程序加载后,code段的段地址是X,则,data段的段地址是X-4H, stack的段地址是 X-2H
在debug中将执行到line17结束、line19之前,记录此时:寄存器(DS) = 076E,寄存器(SS) = 0770,寄存器(CS) = 076C
假设程序加载后,code段的段地址是X,则,data段的段地址是X+2H, stack的段地址是 X+4H
对于如下定义的段,程序加载后,实际分配给该段的内存空间大小是 $\lceil \frac{N}{16} \rceil$ Bytes。
a physical segment can begin only at memory locations evenly divisible by 16[2]
由于 8086 特殊的寻址方式,段首地址只能是 16 的倍数。
使用MASM,实际表现是四个程序均可以运行。使用TASM,无法通过编译。根据 Programmer's Guide[3]:
If you use full segment directives or prefer not to use .STARTUP, you must identify the starting instruction in two steps:
- Label the starting instruction.
- Provide the same label in the END directive.
我认为不指定 starting instruction 的结果是未定义行为是合理的。
assume cs:code code segment start: mov ax, 0B8F0H mov ds, ax mov cx, 160 lb: mov di, cx mov word ptr [di-2], 0403H dec cx loop lb mov ah, 4ch int 21h code ends end start
assume cs:code data1 segment db 50, 48, 50, 50, 0, 48, 49, 0, 48, 49 ; ten numbers data1 ends data2 segment db 0, 0, 0, 0, 47, 0, 0, 47, 0, 0 ; ten numbers data2 ends data3 segment db 16 dup(0) data3 ends code segment start: mov ax, data3 mov es, ax mov cx, 10 mov si, 0 lp: mov ax, data1 mov ds, ax mov ax, ds:[si] mov es:[si], ax mov ax, data2 mov ds, ax mov ax, ds:[si] add es:[si], ax inc si loop lp mov ah, 4ch int 21h code ends end start
before
after
assume cs:code data1 segment dw 2, 0, 4, 9, 2, 0, 1, 9 data1 ends data2 segment dw 8 dup(?) data2 ends code segment start: mov ax, data2 mov es, ax mov ax, data1 mov ds, ax mov si, 0 mov di, 8*2 mov cx, 8 lp: sub di, 2 mov ax, word ptr ds:[si] mov word ptr es:[di], ax add si, 2 loop lp mov ah, 4ch int 21h code ends end start
assume cs:code, ds:data data segment db 'Nuist' db 2, 3, 4, 5, 6 data ends code segment start: mov ax, data mov ds, ax mov ax, 0b800H mov es, ax mov cx, 5 mov si, 0 mov di, 0f00h s: mov al, [si] and al, 0dfh mov es:[di], al mov al, [5+si] mov es:[di+1], al inc si add di, 2 loop s mov ah, 4ch int 21h code ends end start
如果字符为小写,则将这个字符转为大写。
颜色信息。参考VGA text mode。
assume cs:code, ds:data data segment db 'Pink Floyd ' db 'JOAN Baez ' db 'NEIL Young ' db 'Joan Lennon ' data ends code segment start: mov ax, data mov ds, ax mov di, 0 mov cx, 5 lp: add byte ptr [di], 32 add di, 10h loop lp mov ah, 4ch int 21h code ends end start
assume cs:code, ds:data, es:tb, ss:stk data segment db '1975', '1976', '1977', '1978', '1979' dw 16, 22, 382, 1356, 2390 dw 3, 7, 9, 13, 28 data ends tb segment db 5 dup( 16 dup(' ') ) ; tb ends stk segment db 50 dup(0) stk ends code segment start: mov ax, data mov ds, ax mov ax, tb mov es, ax ; field 1 mov cx, 5 _1: push cx mov cx, 4 _2: mov al, [si] mov es:[di], al inc si inc di loop _2 pop cx add di, 10h-4 loop _1 ; field 2 mov di, 5 mov cx, 5 _3: mov ax, word ptr [si] mov word ptr es:[di], ax add si, 2 add di, 10h loop _3 ; field 3 mov di, 10 mov cx, 5 _4: mov ax, word ptr [si] mov es:[di], ax ; signed div mov ax, [si-10] cwd idiv word ptr es:[di] mov es:[di+3], ax add si, 2 add di, 10h loop _4 ext: mov ah, 4ch int 21h code ends end start
before
after
Chapter 2 Organizing Segments, Programmer’s Guide ↩︎
Physical Memory Segments, Programmer’s Guide ↩︎
Specifying a Starting Address, Programmer’s Guide ↩︎