汇编学习第十章
call 和 ret指令
call和ret指令
(都为绝对地址)
call和ret指令都是转移指令,它们都修改IP,或同时修改CS和IP。
(call指令保存的IP是call指令的下一个ip)
它们经常被共同用来实现子程序的设计。
ret和retf
ret指令用栈中的数据,修改IP的内容,从而实现近转移;
retf指令用栈中的数据,修改CS和IP的内容,从而实现远转移。
CPU执行ret指令
0时,进行下面的两步操作:
(1)(IP) = ((ss)*16 +(sp))
(2)(sp) = (sp)+2
CPU执行retf指令时,进行下面四步操作:
(1)(IP) = ((ss)*16) + (sp)
(2)(sp) = (sp) + 2
(3)(CS) = ((ss)*16) + (sp)
(4)(sp) = (sp) + 2
用汇编语法来解释ret和retf指令,则:
CPU执行ret指令时,相当于进行:
pop IP
CPU执行retf指令时,相当于进行:
pop IP
pop CS
例题
1
1 | cs:code,ss:stack |
该题中的程序的数据段和栈段使用了同一段内存 , 也就是说 ds 和 ss 是相同的
执行到 call word ptr ds:[0EH] 的时候 , 具体的流程如下 :
1. CPU取指令 : (call word ptr ds:[0EH])
2. ip自增上述指令的长度 , 指向了下一条指令 (inc ax)
3. 开始执行该指令
3.1. push ip ; 将 ip 压入栈 , 也就是 : ss:[0EH] 保存 ip 的低 8 位 , ss:[0FH] 保存高 8 位
3.2. jmp ds:[0EH] ( (ip) = ds:[0EH] , 也就是说 , 程序又从 ds:[0EH] 中取出数据赋值给 ip , 然后继续执行 )
4. 现在其实就开始执行 ip 之前保存的地址的指令了 , 也就是三个 inc ax
5. 因此最终 ax 值为 3
2
1 | cs:code,ds:data |
这个程序定义了数据段 , 其实也是栈段和数据段使用了同一段内存
首先也是初始化栈 :
mov ax, data
mov ss, ax
mov sp, 16
然后执行 :
mov word ptr ss:[0], offset s
将 s 标号处两个字节的地址移动到 ss:[0] 处
mov ss:[2], cs
将代码段地址的值保存在到 ss:[2] 处 , 同样两个字节
call dword ptr ss:[0]
CPU首先读取该指令
然后将 ip 增加该指令的长度
然后准备开始执行 (由于是 dword 因此 cs 和 ip 都要压栈)
执行首先要将当前的 cs 压栈 (保存在 ss:[0EH])
然后 ip (也就是 call 指令下一个指令的地址 , 也就是 nop 的地址) 压栈 (保存在 ss:[0CH]) 处
然后读取 ss:[0] 中的四个字节的数据 , 相当于 : 高地址为段地址 , 低地址为偏移地址
也就说 cs 为 (ss:[2]) , ip 为 (ss:[0])
这个 cs 和 ip 组成的地址就是 second 的地址
现在开始执行 second
mov ax, offset second
读指令 , ip自增 , 然后执行 , 因此执行完后 , ax 为该指令的偏移地址
然后 sub ax, ss:[0CH]
通过之前的分析 :
ss:[0CH] 处保存的是 : call dword ptr ss:[0] 这条指令的下一条指令 nop 的相对于代码段偏移地址
ax = (mov ax, offset second 的偏移地址) - ( nop 的偏移地址)
也就是 nop 指令的长度 , 也就是 1
接下来 :
mov bx, cs
将代码段的基址赋值给 bx
bx = (bx) - (ss:[0EH])
(ss:[0EH]) = (cs)
因此 bx = 0
实验
计算过程 (以书中的 (F4240H / 0AH) 为例)。
-
int(H/N)*65536
即: 000FH / 000AH = 0001H 余 0005H
所以:int(H/N) = 1H , rem(H/N) = 0005H
int(H/N)*65536 = 10000H -
[rem(H/N)*65536 + L] / N
即: 0005H * 65536 = 50000H
50000H + 4240H = 54240H所以:[rem(H/N)*65536 + L] / N = 54240H / 0AH = 86A0H 余 0000H
-
最终结果:
10000H + 86A0H = 186A0H 且余数为0
分析
第一步中:除法的商为最终结果的商的高16位 ( int(H/N)*65536 )。
第二步中:上一步除法的余数(作为高16位)和被除数的低16位(作为低16位)共同参与32位的除法运算,所得的商为最终结果的商的低16位,所得余数为最终结果的余数。
代码
1 | mov ax,4240H |
注意
cpu在执行指令时先读取当前CS:ip0处的指令,然后IP1=IP0++,此时执行指令如果需要保存IP的话,保存的值已经是IP1了,而不是IP0
例如:
1 | cs:code,ss:stack |
执行到CS:IP4时,CPU首先将此处命令加载到指令缓冲区,然后IP寄存器++ --> IP5 ,然后执行命令: 入栈IP寄存器的值(IP5),然后再…
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Rick!
评论