鱼C论坛

 找回密码
 立即注册
查看: 2528|回复: 0

[学习笔记] 第十章 CALL和RET指令

[复制链接]
发表于 2017-9-21 19:35:03 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

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语言中的函数),注意在子程序中要注意寄存器的冲突问题,记得将冲突的寄存器放在栈中

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-25 01:29

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表