call 和 ret 都是转移指令,都修改IP,或同时修改 CS和IP.
1.1 ret 和 retf
-
ret 指令
用栈中的数据,修改IP的内容,从而实现近转移。
CPU在执行ret指令的时候,进行下面2步操作:
- (IP)=((ss)*16+(sp))
- (sp)=(sp)+2
相当于进行pop IP.
举例:
ret指令执行后,(IP)=0; CS:IP指向代码段的第一条指令。
-
retf指令
用栈中的数据,修改CS和IP的内容,从而实现远转移。(far)
CPU在执行retf指令的时候,进行下面4步操作:
- (IP)=((ss)*16+(sp))
- (sp)=(sp)+2
- (CS)=((ss)*16+(sp))
- (sp)=(sp)+2
相当于:
pop IP
pop CS
举例:
retf指令执行之后,CS:IP指向代码段的第一条指令。
1.2 call 指令
CPU执行call指令时,进行两步操作:
- 将当前的 IP 或 CS和IP 压入栈中。 (这是记录,为了能够回来。)
- 转移
1.2.1 依据位移进行转移的call指令
格式:
call 标号
(将当前IP压栈后,转到标号处执行指令)
CPU执行如下操作:
1.(sp)=(sp)-2 //栈向小伸展,腾出空间
((ss)*16+(sp))=(IP) //将旧IP入栈,相当于 push IP
2.(IP)=(IP)+16位位移 //转移到新IP处,相当于 jmp near ptr 标号。
- 16位位移表示不能实现短转移。
- 16位位移=标号处的地址 – call 指令后的第一个字节的地址。
- 16位位移范围为-32768~32767,用补码表示。
1.2.2 转移的目的地址在指令中的call指令
格式:
call far ptr 标号 实现段间转移
CPU执行如下操作:
1. (sp)=(sp)-2 //栈向小生长,腾出空间
((ss)*16+(sp))=(CS) //CS入栈,相当于,push CS
(sp)=(sp)-2
((ss)*16+(sp))=(IP) //IP入栈,相当于,push IP. 对当前CS IP进行记录
2. (CS)=标号所在段的段地址
(IP)=标号所在段的偏移地址 //赋予新的CS IP,进行 jmp far ptr 标号
1.2.3 转移地址在寄存器中的call指令
格式:
call 16位reg
功能:
1.(sp)=(sp)-2
((ss)*16+(sp)) = (IP) //入栈,记录旧IP ,相当于push IP
2.(IP)=(16位reg) //赋予新IP ,相当于 jmp 16位reg
1.2.4 转移地址在内存中的call指令
- call word ptr 内存单元地址
CPU相当于执行
push IP
jmp word ptr 内存单元地址
举例:
mov sp,10h
mov ax,0123h
mov ds:[0],ax
call word ptr ds:[0]
执行后:
(IP) = 0123H
(sp)=0EH –>栈需要记录IP,需要向小生长空间,则sp=sp-2
- call dword ptr 内存单元地址
CPU相当于执行:
push CS
push IP
jmp dword ptr 内存单元地址
举例:
mov sp,10h
mov ax,0123h
mov ds:[0],ax
mov word ptr ds:[2],0
call dword ptr ds:[0]
执行后,
(CS)=0,(IP)=0123H,
(sp)=0CH —->栈需要记录CS & IP,需要向小生长两次,sp=sp-2-2
1.3 call 和 ret 的配合使用
1.4 mul指令
mul乘法指令:
1.两个相乘的数,要么是8位,要么是16位:
- 如果是8位,一个 默认在AL中,一个放在 8位reg 或 内存字节单元 中。
- 如果是16位,一个默认在AX中,另一个放在 16位reg 或 内存字单元 中。
2.结果:
- 如果是8位乘法,结果默认放在AX中。
- 如果是16位乘法,结果高位默认在DX中存放,低位在AX中存放。
格式:
mul reg
mul 内存单元
其中,内存单元可以用不同的寻址方式给出。
mul
byte ptr ds:[0] //含义:(ax)=(al)*((ds)*16+0) 其中一个值默认在al中。
mul
word ptr [bx+si+8] //含义:(ax)=(ax)*((ds)*16+(bx)+(si)+8)结果的低16位;(dx)=(ax)*((ds)*16+(bx)+(si)+8)结果的高16位;