| 
 | 
 
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册  
 
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语言中的函数),注意在子程序中要注意寄存器的冲突问题,记得将冲突的寄存器放在栈中 |   
 
 
 
 |