马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 若余相思 于 2017-9-21 19:35 编辑
call和ret都是转移指令,它们都修改了IP,或同时修改了CS和IP
10.1节 ret和retf
执行ret执行下面两步操作
(1)(IP) = ((SS) * 16 + (SP))
(2)(SP) = (SP) + 2
相当于执pop ip指令
执行retf执行下面几步操作
(1)(IP) = ((SS) * 16 + (SP))
(2)(SP) = (SP) + 2
(1)(CS) = ((SS) * 16 + (SP))
(2)(SP) = (SP) + 2
相当于执pop ip和pop cs指令
10.3节 依据位移进行转移的call指令
call 标号(将当前的IP压栈后,转到标号处执行指令)
(1)(SP) = (SP) - 2
((SS) * 16 + (SP)) = (IP)
(2)(IP) = (IP) + 16位位移
16位位移 = 标号处的地址 - call指令后的第一个字节的地址
16位位移的范围为 -32768 ~32767
16位位移在编译的时候算出
CPU在执行call 标号时相当于进行
push IP
jmp near ptr 标号
1.4节 转移的目的地址在指令中的call指令
call far ptr 标号,进行如下的操作
(1)(SP) = (SP) - 2
((SS) * 16 + (SP)) = (CS)
(SP) = (SP) - 2
((SS) * 16 + (SP)) = (IP)
(2)CS标号所在的段地址
IP标号所在的偏移地址
CPU执行call far ptr 标号 的时候相当于执行
push CS
push IP
jmp far ptr 标号
10.5节 转移地址在寄存器中的call指令
call 16位reg
功能:
(SP) = (SP) - 2
((SS) * 16 + (SP)) = (IP)
(IP) = (16reg)
相当于push IP
jmp 16位reg
10.6节 转移地址在内存中的call指令
(1)call word ptr 内存单元地址相当于
push IP
call word ptr 内存单元地址
(2)call dword ptr 内存单元地址相当于
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]
10.7节 call和ret的配合使用
程序:mov ax, 1
mov cx, 3
call s
mov bx, ax
mov ax, 4c00H
int 21H
s: add ax, ax
loop s
ret
call s 的时候将IP入栈,然后转到标号处执行代码,执行完后,到ret后将栈中的数据放在IP中,所以会回到call后面的代码执行,程序结束
所以我们得到具有子程序的框架:
assume cs: code
code segment
main : ...
...
call sub
...
...
mov ax, 4c00H
int 21H
sub : ...
...
ret
code ends
end main
10.8节 mul指令
使用mul指令应注意以下两点:
(1)两个数相乘,要么都是8位,要么都是16位。如果是8位,一个默认放在AL中,另一个放在8位的reg或内存字节单元中
如果是16位相乘一个默认放在AX中,另一个放在16位reg或内存字单元中。
(2)结果:如果是8位相乘,结果默认放在AX中;如果是16位相乘,结果默认在DX中存放,低位在AX中放
格式如下:mul reg
mul内存单元
比如:mov al, 100
mov bl 10
mul bl
结果在(ax) = 1000
又比如16位:mov ax, 100
mov bx, 10000
mul bx
结果:(ax) = 4240H, (dx) = 000FH
10.12节 寄存器冲突的问题
因为在主程序中用到的寄存器,在子程序也会用到,所以便会出现寄存器冲突的问题
那么主要的解决的办法就是在进入子程序的时候将用到的寄存器都放在栈中,然后在ret之前,将之前的pop 出栈
比如下面的例子:assume cs: code
data segment
db 'good', 0
db 'link', 0
db 'masm', 0
db 'aini', 0
data ends
code segment
start : mov ax, data
mov ds, ax
mov bx, 0
mov cx, 4
s : mov si, bx
call capital
add bx, 5
loop s
mov ax, 4c00H
int 21H
capital: push cx
push si
change: mov cl, [si]
mov ch, 0
jcxz ok
and byte ptr [si], 11011111B
inc si
loop change
ok :pop si
pop cx
ret
code ends
end start
这样就不会发生寄存器的冲突问题了
总结
(1)本章主要讲ret和call的配合使用
(2)ret是将栈中的数据放在IP中,让CPU转去IP那里执行,retf是将栈的数据都放在CS和IP中执行
(3)call 有多种格式,有call 标号、call near ptr 标号、call word ptr 内存单元、call dword ptr 内存单元和call far ptr 标号,主要功能是将当前的(IP)(前三个)或者同时将(IP)和(CS)(后两个)放在栈中
(4)介绍了乘法指令mul,分8位和16位,8位默认放在al中,16位默认放在ax中
(5)call和ret的配合使用形成了子程序(即C语言中的函数),注意在子程序中要注意寄存器的冲突问题,记得将冲突的寄存器放在栈中 |