本系列教程完全参照王爽《汇编语言(第三版)》,这本书对call、ret指令做了相当一部分的讲解,其重要性可见一斑
从栈的角度分析call和ret
分析以下代码
assume cs:code
stack segment
db 8 dup (0) 1000:0008 00 00 00 00 00 00 00 00
db 8 dup (0) 1000:0000 00 00 00 00 00 00 00 00
stack ends
code segment
start:mov ax,stack 1001:0000 B8 00 10
mov ss,ax 1001:0003 8E 00
mov sp,16 1001:0005 BC 10 00
mov ax,1000 1001:0008 B8 E8 03
call s 1001:000B E8 05 00
mov ax,4c00h 1001:000E B8 00 4C
int 21h 1001:0013 03 C0
s:add ax,ax 1001:0013 03 C0
ret 1001:0015 C3
code ends
end start
分析(从start代码段开始看)
1. 初始化栈CS、IP指针(dup表示重复,共16个0),让SS=1000,SP=16
2. 让(ax) = 1000
前三条指令执行后,如图所示
3. 调用子程序,push下一行的首地址(push 000E,call默认进行near转移)
4. 进入子程序s(CPU从cs:0013H开始执行)
5. ret指令读入,IP首先自增1(这个不重要),CPU接着执行C3处的代码,相当于pop IP,执行后,栈中的情况为
6. CPU回到cs:000EH处继续执行
扫描二维码关注公众号,回复:
1619906 查看本文章
call和ret的配合使用,与高级语言的关系
call指令
push ip
jmp 标号 ; 默认near转移
ret指令(near转移)
pop ip
retf指令(far转移)
pop ip
pop cs
高级语言的程序返回
void foo()
{
printf("foo");
return;
}
高级语言的return
语句通常相当于汇编语言的retf
(远转移)
mul指令
mul
指令用来做乘法,它只能进行8位/8位或16位/16位的乘法
如果是8位/16位乘法,要先将8位用16位数据进行存储(高位补0)
根据参与乘法的两个数的位数,结果保存在ax或ax和dx中