检测点 10.5
(1) 下面的程序执行后,ax 中的数值为多少?(注意:用 call 指令的原理来分析结果,而不要在 Debug 中单步跟踪来验证结论;因为对于此程序,在 Debug 中单步跟踪的结果不能代表 CPU 的实际执行结果。)
assume cs:code
stack segment
dw 8 dup (0)
stack ends
code segment
start: mov ax,stack
mov ss,ax
mov sp,16
mov ds,ax
mov ax,0
call word ptr ds:[0Eh]
inc ax
inc ax
inc ax
mov ax,4c00h
int 21h
code ends
end start
分析:
前面 5 条指令使得 (ss)=(ds),都等于 stack 段地址,而 (sp)=16=10h;“mov ax,0”使得 (ax)=0。接着执行“call word ptr ds:[0Eh]”,先读取该指令后,执行 IP 的自增,使得 CS:IP 指向下一条指令“inc ax”,然后再执行这条 call 指令,执行这条 call 指令相当于:
push IP
jmp word ptr ds:[0Eh]
“push IP”先执行 (sp)=(sp)-2=10h-2=0Eh,然后将 IP(指向的是下一条“inc ax”指令)存入 ds:[0Eh] 字地址(注意是字型数据)。
然后执行“jmp word ptr ds:[0Eh]”,由于当前的 IP 与 ds:[0Eh] 地址存储的字数据值相同,都是指向下面的第 1 条“inc ax”指令,所以程序执行三次“inc ax”使得 (ax)=3(执行前 (ax)=0)。
如果本题前述“程序执行后,ax 中的数值为多少?”是指截止此处的指令,则最终结果就是 (ax)=3。但就程序本身而言,下面还会执行“mov ax,4c00h”指令,这导致 (ax)=4c00h,而这才是整个程序执行的最终结果。
(2) 下面的程序执行后,ax 和 bx 中的数值为多少?
assume cs:code
data segment
dw 8 dup (0)
data ends
code segment
start: mov ax,data
mov ss,ax
mov sp,16
mov word ptr ss:[0],offset s
mov ss:[2],cs
call dword ptr ss:[0]
nop
s: mov ax,offset s
sub ax,ss:[0Ch]
mov bx,cs
sub bx,ss:[0Eh]
mov ax,4c00h
int 21h
code ends
end start
分析:
前面 5 条指令使得 (ss) 等于 data 段地址,而 (sp)=16=10h;并把 s 标号的偏移地址存入 ss:[0] 地址字单元中,把 CS 段寄存器存储的数据存入 ss:[2] 地址字单元中。接着执行“call dword ptr ss:[0]”,先读取该指令后,执行 IP 的自增,使得 CS:IP 指向下一条指令“nop”(这条指令占用 1 个字节内存空间),然后再执行这条 call 指令,执行这条 call 指令相当于:
push CS
push IP
jmp dword ptr ss:[0]
“push CS”先执行 (sp)=(sp)-2=10h-2=0Eh,然后将 CS 段寄存器存储的数据存入 ss:[0Eh] 字地址(注意是字型数据),所以 ss:[0Eh] 所存储的数据就是 CS 段寄存器存储的段地址。
“push IP”先执行 (sp)=(sp)-2=0Eh-2=0Ch,然后将 IP 寄存器存储的数据(这时 IP 指向 nop 空指令)存入 ss:[0Ch] 字地址(注意是字型数据),所以 ss:[0Ch] 存储的字数据就是指令 nop 的偏移地址。
然后执行“jmp dword ptr ss:[0]”,这相当于将地址 ss:[0] 所存储的数据存入 IP 寄存器,而 ss:[0] 所存储的数据就是 s 标号的偏移地址(参第 4 条指令“mov word ptr ss:[0],offset s”),然后将地址 ss:[2] 所存储的数据存入 CS 段寄存器,而 ss:[2] 所存储的数据本就是 CS 段寄存器所存储的数据(参第 5 条指令“mov ss:[2],cs”)。于是程序跳至 s 标号处执行:
mov ax,offset s
sub ax,ss:[0Ch]
首先将 s 标号的偏移地址存入 AX 寄存器,然后将 AX 寄存器存储的数据减去 ss:[0Ch] 地址所存储的字数据,并将结果存入 AX 寄存器;由于 ss:[0Ch] 地址存储的字数据就是 nop 指令的偏移地址,可见进行相减运算就是将 s 标号偏移地址减去 nop 指令所在内存单元的偏移地址 —— 由于 nop 指令占用 1 个字节,所以相减的结果等于 1,所以 (ax)=1。
接着执行:
mov bx,cs
sub bx,ss:[0Eh]
由于 ss:[0Eh] 存储的数据就是 CS 段寄存器存储的段地址,因此执行的结果是 (bx)=0。
与前述 (1) 一样,如果本题前述“程序执行后,ax 中的数值为多少?”是指截止此处的指令,则最终结果就是 (ax)=1,(bx)=0。但就程序本身而言,下面还会执行“mov ax,4c00h”指令,这导致 (ax)=4c00h,而这才是整个程序执行的最终结果,也就是 (ax)=4c00h,(bx)=0。