汇编指令jmp的理解
在学习汇编语言的时候遇到下面一段代码,起初简单地认为这个程序是不能正常结束的。但是经过debug单步跟踪之后,发现程序是能正常结束的,且出现了一种奇怪的现象:当程序从code:0005处开始执行到code:0014后,继续jmp指令跳到code:0008。然而,继续往前执行一步时,程序直接跳转到了code:0处,而不是预先想象的跳到code:0018(即标号s1段处)。起初并不理解这是怎么回事,经过多次单步跟踪观察仍然感到怪异。仔细研读教科书[1]关于jmp指令的用法后,再结合机器码对程序进行分析,对jmp指令有了更多新的理解。
汇编代码 地址偏移(IP) 机器指令
assume cs:code (单位:h)
code segment
mov ax,4c00h 0000 B8004C
int 21h 0003 CD21
start: mov ax,0 0005 B80000
s: nop 0008 90
nop 0009 90
mov di,offset s 000A BF0800
mov si,offset s2 000D BE2000
mov ax,cs:[si] CS:0020=F6EB
mov cs:[di],ax CS:0008=9090
s0: jmp short s 0016 EBF0
s1: mov ax,0 0018 B80000
int 21h 001B CD21
mov ax,0 001D B80000
s2: jmp short s1 0020 EBF6
nop 0022 90
code ends
end start
一、下面两条需要理解清楚
1、CPU指令执行的过程如下:
<1>、从CS:IP指向的内存单元读取指令,并将其放入指令缓冲器。
<2>、IP=IP+当前被读取进入缓冲器的指令长度,即IP指向下一条指令。
<3>、执行缓冲器中的当前指令。转到步骤<1>
2、段内段转移jmp short ?指令的意义
<1>、IP是偏移量,即IP=标号处的地址-jmp指令后第一个字节的地址。
<2>、该指令的功能就是修改IP的值,执行该指令后IP=IP+8位偏移量
<3>、8位位移范围为-128~127,且偏移是用补码[2]的形式表示。
二、代码分析
1、第一步:程序从入口start(code:0005)处开始执行,当执行完code:0013~0014语句之后,标号s2处的语句jmp short s1的机器码被复制到code:0008中,IP为0016。此时,假定没有jmp short s指令,则程序会执行到s2:jmp short s1处,读jmp short s1入指令缓冲器后IP=0022;而s2到s1的转移为段内段转移,机器码格式为EB disp,且disp=标号s1-标号s2=(00018-0022)的补码=F6,所以指令jmp short s1的机器码应为EBF6。因此,EBF6被复制到code:0008~code:0009单元中。
2、第二步:将指令jmp short s(EBF0)读入指令缓冲器,
IP=IP+0002=0018;标号s-标号s0=(0008-0018)的补码=F0,而s0到s的转移为段内段转移,机器码格式为EB disp(即EBF0)
3、第三步:指令jmp short s(EBF0)是一条修改IP的指令,执行指令EBF0后,IP=IP+(标号s-标号s0)=0008,指向code:0008单元。
4、第四步:读取code:0008单元的内容。由于s2处的指令jmp short s1(EBF6)被复制到code:0008~code:0009单元,所以读取该单元的内容后,IP=IP+0002=000A
5、第五步:指令jmp short s1(EBF6)是一条修改IP的指令,执行指令EBF6后,IP=IP+(标号s1-标号s2)=0000,指向code:0000单元。
6、第六步:程序转到code:0000处执行,即完成了正常结束。
三、后记
正确分析这段代码:需要理解CPU指令执行的过程以及jmp short ?中标号?的地址计算方法(通过IP修改来计算的)。另外,偏移的计算结果取补码也是一个关键。通过对这段看似不正常的代码进行分析之后,对汇编中的jmp指令有了更深层次的理解。
[参考文献]
[1] 王爽.汇编语言(第二版)[M].北京:清华大学出版社;2008:176-184
[2] 谭浩强.C程序设计[M].北京:清华大学出版社;