call 和 ret 指令都是转移指令,用来修改IP,或者同时修改CS 和 IP。通常用与实现子程序的设计。
1. ret 和 retf
ret指令用栈中的数据修改IP内容,从而实现近转移
retf指令用栈中的数据修改CS和IP的内容,从而实现远转移
CPU执行ret指令时,进行如下操作:
(1)(IP)=((ss)*16+sp) 这个就是取栈顶的数据
(2)(sp)=(sp)+2 栈顶地址下移
CPU执行retf指令时,执行4步:
(1)(IP)=((ss)*16+sp) 和上面同理
(2)(sp)=(sp)+2
(3)(CS)=((ss)*16+sp)
(4)(sp)=(sp)+2
因此,CPU执行ret指令时,相当于进行:pop IP
执行retf指令时,相当于执行:pop IP,pop CS
2. call指令
CPU执行call指令执行:
(1)将当前的IP或CS和IP压入栈中;
(2)转移。
3. 依据位移进行转移的call指令
call 标号(将当前的IP压栈后,转到标号处执行指令)
CPU执行这种格式的call指令时,执行:
(1)(sp)=(sp)-2
((ss)*16+sp))=(IP)
(2)(IP)=(IP)+16位位移
16位位移=标号处的地址-call指令后的第一个字节的地址
16位位移的范围为-32768~32767,用补码表示。
16位位移有编译程序在编译时算出。
检测点10.2
下面的程序执行后,ax中的数值为多少?
内存地址: 机器码 汇编指令
1000: 0 b8 00 00 mov ax,0
1000:3 e8 01 00 call s
1000: 6 40 inc ax
1000:7 58 s:pop ax
call在执行时,进行两步操作:
1. 将当前的IP压栈,这里的IP是当前指令的下一条指令的IP值。这里是6
2. 转入标号指令运行,这里转到s处运行,执行pop ax,因此ax的值为6.
(注意,这里的栈是系统自动创建的)
4. 转移的目的地址在指令中的call指令
call far ptr 标号
实现段间转移。
CPU执行是,执行如下:
(1)(sp)=(sp)-2
((ss)*16+(sp))=(CS)
(sp)=(sp)-2
((ss)*16+(sp))=(IP)
(2)(CS)=标号所在段的段地址
(IP)=标号所在段的偏移地址
5. 转移地址在寄存器中的call指令
格式:call 16位 reg (reg:register)
功能:
(sp)=(sp)-2
((ss)*16+(sp))=(IP)
(IP)=(16位reg)
类似于:
push IP
jmp 16位 reg
6. 转移指令在内存中的call命令
call word ptr 内存单元地址
相当于:push IP // jmp word ptr
call dword ptr 内存单元地址
相当于:push CS // push IP // jmp dword ptr 内存单元地址