(1)将下面的程序编译连接,用Debug加载、跟踪,然后回答问题:
assume cs:code,ds:data,ss:stack
data segment
dw 0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H
data ends
stack segment
dw 0,0,0,0,0,0,0,0
stack ends
code segment
start:mov ax,stack
mov ss,ax
mov sp,16
mov ax,data
mov ds,ax
push ds:[0]
push ds:[2]
pop ds:[2]
pop ds:[0]
mov ax,4c00H
int 21H
code ends
end start
a.CPU执行程序,程序返回前,data段的内容是多少?
无需debug调试, push ds:[0],push ds:[2]后,[2]在栈顶,经过
pop ds:[2],pop ds:[0],栈顶先出栈,所以程序数据段依然没有变化。所以程序返回前,data中的数据为:
0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H
b.CPU执行程序,程序返回前,cs=____,ss=______,ds=______
尽管可以用code,stack,data之类的标号来赋值,如cs=code,ss=stack,ds=data。不过,不同机器加载程序后,-t测试完后,会有具体的cs,ss和ds数值。我这边测试结果为cs=13F8,ss=13F7,ds=13F6
c.设程序加载后,code段的段地址为X,则data段的段地址为___,stack段的段地址为___。
根据第二小问得出的计算结果为,data=X-2,stack=X-1。但如果根据下面的理解得到结果,或许更好,即:
C:\masm>debug p61.exe
-r
AX=0000 BX=0000 CX=0042 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=13E6 ES=13E6 SS=13F6 CS=13F8 IP=0000 NV UP EI PL NZ NA PO NC
13F8:0000 B8F713 MOV AX,13F7
-d 13e6:100
13E6:0100 23 01 56 04 89 07 BC 0A-EF 0D ED 0F BA 0C 87 09 #.V.............
13E6:0110 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
13E6:0120 B8 F7 13 8E D0 BC 10 00-B8 F6 13 8E D8 FF 36 00 ..............6.
13E6:0130 00 FF 36 02 00 8F 06 02-00 8F 06 00 00 B8 00 4C ..6............L
13E6:0140 CD 21 00 00 00 00 F9 13-FB 0D 22 00 E6 13 02 32 .!........"....2
13E6:0150 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
13E6:0160 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
13E6:0170 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
-u
13F8:0000 B8F713 MOV AX,13F7
13F8:0003 8ED0 MOV SS,AX
13F8:0005 BC1000 MOV SP,0010
13F8:0008 B8F613 MOV AX,13F6
13F8:000B 8ED8 MOV DS,AX
13F8:000D FF360000 PUSH [0000]
13F8:0011 FF360200 PUSH [0002]
13F8:0015 8F060200 POP [0002]
13F8:0019 8F060000 POP [0000]
13F8:001D B8004C MOV AX,4C00
-u
13F8:0020 CD21 INT 21
13F8:0022 0000 ADD [BX+SI],AL
13F8:0024 0000 ADD [BX+SI],AL
13F8:0026 F9 STC
13F8:0027 13FB ADC DI,BX
13F8:0029 0D2200 OR AX,0022
13F8:002C E613 OUT 13,AL
13F8:002E 0232 ADD DH,[BP+SI]
13F8:0030 0000 ADD [BX+SI],AL
13F8:0032 0000 ADD [BX+SI],AL
13F8:0034 0000 ADD [BX+SI],AL
13F8:0036 0000 ADD [BX+SI],AL
13F8:0038 0000 ADD [BX+SI],AL
13F8:003A 0000 ADD [BX+SI],AL
13F8:003C 0000 ADD [BX+SI],AL
13F8:003E 0000 ADD [BX+SI],AL
可知data段占据第一排(根据-d显示结果的方式,即每16个存储单元显示为一排),而data段共8个字型数据,故刚好占据一排空间,接下来就是stack段,也刚好占据一排,根据-u的结果可知,stack段下面一排存放的就是code代码段。因此可知,data段初始地址比code段小2排(即32个内存单元),stack的比code的小1排(即16个内存单元)。所以,
code*16+0-(data*16+0)=2*16,而code=X,所以,data=X-2,同理,stack=X-1。
(2)将下面的程序编译连接,用Debug加载、跟踪,然后回答问题:
assume cs:code,ds:data,ss:stack
data segment
dw 0123H,0456H
data ends
stack segment
dw 0,0
stack ends
code segment
start:mov ax,stack
mov ss,ax
mov sp,16
mov ax,data
mov ds,ax
push ds:[0]
push ds:[2]
pop ds:[2]
pop ds:[0]
mov ax,4c00H
int 21H
code ends
end start
a.CPU执行程序,程序返回前,data段的内容是多少?
跟前面一样,data段的内容不便,依然为: 0123H,0456H
b.CPU执行程序,程序返回前,cs=____,ss=______,ds=______
还是可以用cs=code,ss=stack,ds=data表示。具体执行时,不同的机器得出额结果不一样,我的机器给出的是,cs=13F8,ss=13F7,ds=13F6
c.设程序加载后,code段的段地址为X,则data段的段地址为___,stack段的段地址为___。
根据上面额结果,可知data=X-2,stack=X-1。
也可以先用Debug加载p62.exe,再用-d和-u指令计算data和stack段的段地址,如题1一样。只不过,这里的data和stack段的数据所占空间为4个内存单元,不足一排,但仍要占据一排。所以结果跟题1一样。
d.对于如下定义的段:
name segment
...
name ends
如果段中的数据占N个字节,则程序加载后,该段实际占有的空间为__。
段中的数据占N个字节,意味着占N个存储单元,在debug调试中输入-t后,显示以16个存储单元为一排。因此,用N/16表示占有几排,如果商为零,表示不足一排,仍给它一排的空间,也可写成(N/16+1)*16,如题2中
data segment
dw 0123H,0456H
data ends
stack segment
dw 0,0
stack ends;
此外,题3中也是这样的。
如果商刚好为整数t,表明则就占据t排空间,则实际占有空间为(N/16)*16,如题1中,
data segment
dw 0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H
data ends
stack segment
dw 0,0,0,0,0,0,0,0
stack ends;
若商为t,还带有余数,表明t排空间不够,t+1排又填不满,不过仍让填不满空间的一排占有一排,所以为t+1排,则实际占有空间为(N/16+1)*16。其中(N/16)都只取商的整数部分,小数部分去掉。
因此,看了参考答案后,就写做(N/16+1)*16,恐怕不对吧。按照这个等式,像下面的段按照N/16+1)*16计算,应该占有(16/16+1)*16=32个存储单元,可是16个存储单元足以填充这些数据。
data segment
dw 0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H
data ends
那么用实验来证明,在用masm和link得到题1中的可执行文件(我这边的文件为p61.exe)后,进入cmd后,切换到c:\masm目录中。结果如下。
C:\masm>debug p61.exe
-r
AX=0000 BX=0000 CX=0042 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=13E6 ES=13E6 SS=13F6 CS=13F8 IP=0000 NV UP EI PL NZ NA PO NC
13F8:0000 B8F713 MOV AX,13F7
-d 13e6:100
13E6:0100 23 01 56 04 89 07 BC 0A-EF 0D ED 0F BA 0C 87 09 #.V.............
13E6:0110 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
13E6:0120 B8 F7 13 8E D0 BC 10 00-B8 F6 13 8E D8 FF 36 00 ..............6.
13E6:0130 00 FF 36 02 00 8F 06 02-00 8F 06 00 00 B8 00 4C ..6............L
13E6:0140 CD 21 00 00 00 00 00 00-00 00 00 00 00 00 00 00 .!..............
13E6:0150 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
13E6:0160 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
13E6:0170 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
其中第一排结果是data段占据的实际空间为,16个存储单元,此外,stack段也是如此,只占16个存储单元。
(3)将下面的程序编译连接,用Debug加载、跟踪,然后回答问题:
assume cs:code,ds:data,ss:stack
code segment
start:mov ax,stack
mov ss,ax
mov sp,16
mov ax,data
mov ds,ax
push ds:[0]
push ds:[2]
pop ds:[2]
pop ds:[0]
mov ax,4c00H
int 21H
code ends
data segment
dw 0123H,0456H
data ends
stack segment
dw 0,0
stack ends
end start
a.CPU执行程序,程序返回前,data段的内容是多少?
与前面一样,依然为0123H,0456H。
b.CPU执行程序,程序返回前,cs=____,ss=______,ds=______
还是可以用cs=code,ss=stack,ds=data表示。具体执行时,不同的机器得出额结果不一样,我的机器给出的是,cs=13F6,ss=13FA,ds=13F9
c.设程序加载后,code段的段地址为X,则data段的段地址为___,stack段的段地址为___。
C:\masm>debug p63.exe
-r
AX=0000 BX=0000 CX=0044 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=13E6 ES=13E6 SS=13F6 CS=13F6 IP=0000 NV UP EI PL NZ NA PO NC
13F6:0000 B8FA13 MOV AX,13FA
-d 13E6:100
13E6:0100 B8 FA 13 8E D0 BC 10 00-B8 F9 13 8E D8 FF 36 00 ..............6.
13E6:0110 00 FF 36 02 00 8F 06 02-00 8F 06 00 00 B8 00 4C ..6............L
13E6:0120 CD 21 00 00 00 00 00 00-00 00 00 00 00 00 00 00 .!..............
13E6:0130 23 01 56 04 00 00 00 00-00 00 00 00 00 00 00 00 #.V.............
13E6:0140 00 00 00 00 00 00 F9 13-FB 0D 22 00 E6 13 02 32 .........."....2
13E6:0150 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
13E6:0160 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
13E6:0170 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
-u
13F6:0000 B8FA13 MOV AX,13FA
13F6:0003 8ED0 MOV SS,AX
13F6:0005 BC1000 MOV SP,0010
13F6:0008 B8F913 MOV AX,13F9
13F6:000B 8ED8 MOV DS,AX
13F6:000D FF360000 PUSH [0000]
13F6:0011 FF360200 PUSH [0002]
13F6:0015 8F060200 POP [0002]
13F6:0019 8F060000 POP [0000]
13F6:001D B8004C MOV AX,4C00
-u
13F6:0020 CD21 INT 21
13F6:0022 0000 ADD [BX+SI],AL
13F6:0024 0000 ADD [BX+SI],AL
13F6:0026 0000 ADD [BX+SI],AL
13F6:0028 0000 ADD [BX+SI],AL
13F6:002A 0000 ADD [BX+SI],AL
13F6:002C 0000 ADD [BX+SI],AL
13F6:002E 0000 ADD [BX+SI],AL
13F6:0030 2301 AND AX,[BX+DI]
可知INT 21汇编指令对应的机器指令是位于13F6:0020的CD21。
根据-d 13E6:100显示的结果可知,代码段code占据3排,而且3排没有排满,因为第三排中只有最前面两个内存单元被使用,为CD 21即该段程序的最后一条指令的机器码。尽管没有排满,但仍要占据一排。跟在code段后面的是data,然后才是stack段。所以data的初始地址比代码段的初始地址要大3排,即(16×data+0)-(16×X+0)=3×16,所以
data=X+3。而data段只有2两个字型数据,占有4个内存单元,不足一排,根据公式,仍得占据一排,所以stack段的初始地址跟data段的相差一个一排,即16个内存单元。所以stack×16+0-data×16-0=16所以,stack=data+1=X+4。
(4)如果将1、2、3题中的最后一条伪指令"end start"改为"end"(也就是说,不指明程序的入口),则哪个程序仍然可以正确执行?请说明原因。
只有3题中可以正常运行。因为3题中,code段在最前面,cs:0直接指向code代码段,所以可以运行。而1和2题中,则是代码段放在最后,data段放在最前,所以cs:0指向data段,当然不会正确执行。
(5)程序如下,编写code段中的代码,将a段和b段中的数据依次相加,将结果存到c段中。
assume cs:code
a segment
db 1,2,3,4,5,6,7,8
a ends
b segment
db 1,2,3,4,5,6,7,8
b ends
c segment
db 0,0,0,0,0,0,0,0
c ends
code segment
start:
?
code ends
end start
首先根据题1、2和3中的理解,a、b和c段存放的都是8个字节型数据,占据8个内存空间,不足一排,但仍要占据一排,且根据段排列的先后顺序可知,b段的段地址要比a段的大16,c段的段地址要比a的大32。据此,编写如下。
缺少的指令代码如下:
mov ax,a
mov ds,ax
mov bx,0
mov cx,8
s:mov dl,[bx]
mov dh,0
mov al,[bx+16]
mov ah,0
add ax,dx
mov [bx+32],al
inc bx
loop s
mov ax,4c00H
int 21H
将上面的程序命名为p65.asm,经过编译连接后产生名为p65.exe的可执行文件。
C:\masm>debug p65.exe
-r
AX=0000 BX=0000 CX=004D DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=13E6 ES=13E6 SS=13F6 CS=13F9 IP=0000 NV UP EI PL NZ NA PO NC
13F9:0000 B8F613 MOV AX,13F6
-d 13e6:100
13E6:0100 01 02 03 04 05 06 07 08-00 00 00 00 00 00 00 00 ................
13E6:0110 01 02 03 04 05 06 07 08-00 00 00 00 00 00 00 00 ................
13E6:0120 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
13E6:0130 B8 F6 13 8E D8 BB 00 00-B9 08 00 8A 17 8A 47 10 ..............G.
13E6:0140 02 C2 88 47 20 43 E2 F3-B8 00 4C CD 21 C0 22 80 ...G C....L.!.".
13E6:0150 3E 45 07 00 74 0A FF 36-56 07 E8 21 FC 83 C4 02 >E..t..6V..!....
13E6:0160 FF 06 56 07 5E 8B E5 5D-C3 90 55 8B EC 81 EC 90 ..V.^..]..U.....
13E6:0170 00 56 C4 5E 06 26 8B 47-08 89 46 F8 26 83 7F 06 .V.^.&.G..F.&...
-u
13F9:0000 B8F613 MOV AX,13F6
13F9:0003 8ED8 MOV DS,AX
13F9:0005 BB0000 MOV BX,0000
13F9:0008 B90800 MOV CX,0008
13F9:000B 8A17 MOV DL,[BX]
13F9:000D 8A4710 MOV AL,[BX+10]
13F9:0010 02C2 ADD AL,DL
13F9:0012 884720 MOV [BX+20],AL
13F9:0015 43 INC BX
13F9:0016 E2F3 LOOP 000B
13F9:0018 B8004C MOV AX,4C00
13F9:001B CD21 INT 21
13F9:001D C0 DB C0
13F9:001E 22803E45 AND AL,[BX+SI+453E]
-t
AX=13F6 BX=0000 CX=004D DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=13E6 ES=13E6 SS=13F6 CS=13F9 IP=0003 NV UP EI PL NZ NA PO NC
13F9:0003 8ED8 MOV DS,AX
-g 0018
AX=1310 BX=0008 CX=0000 DX=0008 SP=0000 BP=0000 SI=0000 DI=0000
DS=13F6 ES=13E6 SS=13F6 CS=13F9 IP=0018 NV UP EI PL NZ NA PO NC
13F9:0018 B8004C MOV AX,4C00
-t
AX=4C00 BX=0008 CX=0000 DX=0008 SP=0000 BP=0000 SI=0000 DI=0000
DS=13F6 ES=13E6 SS=13F6 CS=13F9 IP=001B NV UP EI PL NZ NA PO NC
13F9:001B CD21 INT 21
-g
Program terminated normally
-d 13e6:100
13E6:0100 01 02 03 04 05 06 07 08-00 00 00 00 00 00 00 00 ................
13E6:0110 01 02 03 04 05 06 07 08-00 00 00 00 00 00 00 00 ................
13E6:0120 02 04 06 08 0A 0C 0E 10-00 00 00 00 00 00 00 00 ................
13E6:0130 B8 F6 13 8E D8 BB 00 00-B9 08 00 8A 17 8A 47 10 ..............G.
13E6:0140 02 C2 88 47 20 43 E2 F3-B8 00 4C CD 21 C0 22 80 ...G C....L.!.".
13E6:0150 3E 45 07 00 74 0A FF 36-56 07 E8 21 FC 83 C4 02 >E..t..6V..!....
13E6:0160 FF 06 56 07 5E 8B E5 5D-C3 90 55 8B EC 81 EC 90 ..V.^..]..U.....
13E6:0170 00 56 C4 5E 06 26 8B 47-08 89 46 F8 26 83 7F 06 .V.^.&.G..F.&...
发现,第三排为前两排数之和。说明该编程有效。好开心啊。呵呵。
(6)程序如下,编写code段中的代码,用push指令将a段中word数据,逆序存储到b段中。
assume cs:code
a segment
dw 1,2,3,4,5,6,7,8
a ends
b segment
dw 0,0,0,0,0,0,0,0
b ends
code segment
start:
?
code ends
end start
逆序排列,用入栈和出栈编程,再好不过的了。缺失的代码为
mov ax,a
mov ds,ax
mov ss,b
mov sp,20H
mov bx,0
mov cx,8
s:push [bx]
inc bx
inc bx
loop s
mov ax,4c00H
int 21H