前几天,千哥在发表了《千哥读书笔记:汇编语言(王爽第四版)第8章实验七》以后,又有朋友问,汇编语言(王爽第四版)第9章 实验八,完全搞不懂。下面,千哥再来逐一解析。
实验八:
分析下面的程序,在运行前思考,这个程序可以正确返回吗?
先来看完整的代码:
=========这是代码与内容的分割线==========
assume cs:codesg
codesg segment
mov ax,4c00h
int 21h
start: mov ax,4
s: nop
nop
mov di,offset s
mov si,offset s2
mov ax,cs:[si]
mov cs:[di],ax
s0:jmp short s
s1:mov ax,0
int 21h
mov ax,0
s2:jmp short s1
nop
codesg ends
end start
=========这是代码与内容的分割线==========
编译成p9108.exe,在DEBUG下调试,程序入口在076a:0005处,用 u 076a:0005观察:
从076A:0008至076A:0009处,可以观察到定义了两个nop(机器码90 90)
然后执行:
mov di,offset s
mov si,offset s2
可以看出,offset s的偏移量是0008,offset s2的偏移量是0020,分别赋值给di和si,接下来,执行:
mov ax,cs:[si]
mov cs:[di],ax
也就是说,将 076A:0020的内容,赋值给AX,AX再将这个内容,赋值给076A:0008。那么, 076A:0020的内容是多少呢?看下图:
076A:0020的机器码是EBF6,对应的指令是JMP 0018。也就是说,在执行mov cs:[di],ax时,要将EBF6这个机器码,传送到076A:0008至076A:0009这两个节字的内存单元。
在执行完上面这些指令以后:
下一条指令,就是JMP 0008,也就是即将执行jmp short s,也就是将执行传送到076A:0008里的EBF6。在这里,魔法就出来了:
我们在前面知道,076A:0020的机器码是EBF6,对应的指令是JMP 0018,而076A:0018后面对应的指令是:
s1:mov ax,0
int 21h
mov ax,0
在S1这个位置,就是076A:0018,因为这段代码:s2:jmp short s1 所在的位置,就是076A:0020,显示的指令就是JMP 0018,现在就是要执行从076A:0018开始的代码,也就是 mov ax,0
当执行了mov ax,0以后, int 21H会从AX中获取返回码,此时是0。所以,复制在076A:0008至076A:0009处的机器码EBF6,应对的指令,就不再是JMP 0018,而变成了 JMP 0000:
大家可以看到,0076A:0020 处的机器码是EBF6,对应的指令明明是 JMP 0018;而在把这个机器码EBF6复制到0076A:0008以后,对应的指令却变成了JMP 0000。说明在复制的过程中,是执行过mov ax,0和 int 21h的。
而在执行 JMP 0000,就跳转到mov ax,4c00h:
最后再执行 int 21h:
AX被设为4C00H,int 21H从AX中获取返回码,程序正常结束。程序正确返回,打完收工。
这个程序主要探究的是int 21H的作⽤。其中的奥妙在于:
1、jmp short 标号,这个指令,并不显示绝对地址,标号所反映的,只是计算偏移量的相对地址,所以 JMP 0018和 JMP 0000显示的机器码都是F6EB
2、int 21H会自动从AX获取返回码,并决定程序是否能够正确返回。
3、机器在执行相应命令的时候,会自动生成中间变量,但这些中间变量不会在debug中显示。