call和ret都是用来修改ip或cs:ip,可以用来实现子程序的设计;
 
1.ret和retf
ret    ->修改ip的内容,从而实现近转移;
retf    ->同时修改cs和ip,从而实现远转移;
 
执行ret时:相当于 pop ip
    1】(ip)=((ss)*16+(sp));也就是将栈顶的值赋值给ip;
    2】(sp)=(sp)+2;也就是栈顶指向栈的下一个字;
执行retf时:相当于pop ip,pop cs
    1】(ip)=((ss)*16+(sp))
    2】(sp)=(sp)+2
    3】(cs)=((ss)*16+(sp))
    4】(sp)=(sp)+2
 
例如:下面的程序执行retf后,cs:ip指向代码第一条指令,也就是程序返回的代码 mov ax,4cooh
stack segment
    db 16 dup (0)
stack ends
code segment
    mov ax,4c00h
    int 21h
    start:mov ax,stack
            mov ss,ax
            mov sp,16
            mov ax,0
            push cs
            push ax
            retf
code ends
 
2.call指令
call    ->将当前的ip或cs:ip压入栈中,然后转移;
call指令和jmp指令相似,但不能实现短转移,有多种格式;
 
1)依据位移进行转移的call指令
格式:
    call 标号
例如:
call start
执行的操作:将当前的ip压入栈后转移到标号处执行指令;
    1】(sp)=(sp)-2,((ss)*16+(sp))=(ip)
    2】(ip)=(ip)+16位位移
        2.1】16位位移=标号处的地址-call指令后的第一个字节的地址
        2.2】16位的位移范围是-32768~32767
        2.3】16位位移在编译时由编译器计算出来
相当于:
    push ip
    jmp near ptr 标号
 
2)转移目标地址在指令中的call指令
格式:
    call far ptr 标号
例如:
call far ptr s
执行的操作:段间转移,将当前cs和ip分别入栈后转移到标号处;
    1】(sp)=(sp)-2
        ((ss)*16+(sp))=(cs)
        (sp)=(sp)-2
        ((ss)*16+(sp))=(ip)
    2】(cs)=标号所在段的段地址
        (ip)=标号所在段的偏移地址
相当于:
    push cs
    push ip
    jmp far ptr 标号
 
3)转移目标地址在寄存器中的call指令
格式:
    call 16位寄存器
例如:
call ax
执行的操作:当前ip入栈,ip的值设为寄存器中的值
    (sp)=(sp)-2
    ((ss)*16+sp)=(ip)
    (ip)=16位寄存器的值
相当于:
    push ip
    jmp 16位寄存器
 
4)转移地址在内存中的call指令
有两种格式:
    1】call word ptr 内存单元地址
call word ptr ds:[0]
          相当于:
            push ip
            jmp word ptr 内存单元地址
  2】call dword ptr 内存单元地址
call dword ptr ds:[0]
        相当于:
            push cs
            push ip
            jmp dword ptr 内存单元地址
 
3.call和ret配合使用
利用call和ret配合,可以实现具有一定功能的程序的,也叫子程序;
用call指令执行子程序中的代码,将后面的指令地址入栈;
执行完子程序后用ret指令用栈中的数据设置ip,依次保证程序继续向下执行;
 
框架:
例如:下面是计算2的3次方的代码
assume cs:code,ss:stack
stack segment
    db 8 dup (0)
    dp 8 dup (0)
stack ends
code segment
    start:mov ax,stack
        mov ss,ax
        mov sp,16
        mov ax,1000
        call s
        mov ax,4c00h
        int 21h
    s:  add ax,ax
        ret
code ends
end start
 
4.mul指令
mul是乘法指令;
 
格式:
    1】mul 寄存器   
mul ax
    2】mul 内存单元
mul byte ptr ds:[0]
mul word ptr ds:[0]
 
执行过程:
    两个数相乘,要么都是8位,要么都是16位;
    如果都是8位,一个默认放在al中,另一个放在8位寄存器或内存字节单元中;
    如果都是16位,一个默认在ax中,另一个放在16位寄存器或内存字单元中;
执行结果:
    如果是两个8位的数相乘,结果默认放在ax中;
    如果两个16位的数相乘,结果高位在dx中,低位在ax中;
 
例如:计算100*10000,因为10000大于255超出了8位的限制,只能做16位乘法
mov ax,100
mov bx,10000
mul bx
 
5.参数和结果的传递
子程序一般根据提供的参数处理后将结果返回给调用者;
因此需要考虑参数和结果的储存在哪的问题;
 
1)用寄存器来储存参数和结果
调用者将参数存入参数寄存器,从结果寄存器中获取返回值;
子程序从参数寄存器中获取参数,将处理结果存入结果寄存器;
 
例如:计算3次方的子程序
        ;...省略
        mov bx,5
        call cube        ;调用子程序,用bx作参数寄存器
        mov ds:[0],ax    ;从结果寄存器ax,dx中获取结果的低位和高位
        mov ds:[2],dx
cube:   mov ax,bx    ;计算3次方的子程序
            mul bx
            mul bx
 
 
2)批量数据的传递
如果参数或结果较少,可以用寄存器来存放;
但是如果有参数过多,就不太合适了,因为寄存器的数量有限;
可以考虑将批量数据存放在内存中,寄存器中存放数据所在内存的首地址、cx中存放数据长度、用loop指令循环调取;
 
例如:将字符串转为大写
assume cs:code,ds:data
data segment
    db 'helloworld'
data ends
 
code segment
    start:  mov ax,data
            mov ds,ax
            mov si,0     ;ds:[si]存放数据首地址
            mov cx,10    ;cx存放数据长度长度
            call method
            mov ax,4c00h
            int 21h
    method: and byte ptr [si],11011111b    ;转为大写
            inc si
            loop method
            ret            
code ends
end start
 
3)用栈传递参数
这种技术常用在高级语言编译器中;
例如:计算(3-1)的3次方
        mov ax,1
        push ax    ;将参数压入栈中
        mov ax,3
        push ax    ;注意入栈顺序
        call difcube
        mov ax,4c00h
        int 21h
 
difcube: push bp        ;将bp原来的值入栈,处理完后再pop回去
        mov bp,sp
        mov ax,[bp+4]    ;将栈中的值3送入ax
        sub ax,[bp+6]    ;3-1=2,将2送入ax
        mov bp,ax
        mul bp
        mul bp
        pop bp
        ret 4        ;程序返回,并且将栈顶回复到初始状态,因为两个参数还占4个字节的空间,所以sp要多移动4个字节
栈的变化:
 
6.寄存器的冲突
如果子程序中需要用到调用者使用的寄存器时,可能产生冲突;
例如:调用者为了做循环需要用到寄存器cx,子程序中也需要做循环也要用到cx;
    而子程序循环完成后cx的值已经被修改了,调用者因此受到了影响;
解决思路:
    1】避免在子程序中使用调用者用过的寄存器;
    2】避免在调用者中使用子程序用过的寄存器;
问题:
    因为调用的不确定性,上面两种方案行不通,我们希望编写子程序和调用者时不要被寄存器的冲突限制;
可行方案:
    可以考虑在编写子程序时,将子程序需要使用的寄存器值先入栈;
    当子程序执行完后,在出栈,将寄存器的值还原;
例如:
method:push cx    ;用到的寄存器入栈
    push si
    ;...业务代码,需要用到寄存器cx和si
ok:    pop si    ;业务代码完成后,寄存器出栈还原,主义出栈顺序
        pop cx
        ret
 
 
 

call和ret指令的更多相关文章

  1. 汇编语言---call和ret指令

    汇编语言--call和ret指令 call和ret指令 call和ret指令都是转移指令,它们都修改IP,或同时修改CS和IP. 它们经常被共同用来实现子程序的设计. ret和retf ret指令用栈 ...

  2. 汇编学习笔记(7)call和ret指令

    ret和retf CPU执行ret指令时进行以下两步操作: (IP)=((ss)*16+(sp)) (sp)=(sp)+2 这相当于pop IP CPU执行retf指令时进行以下四步操作: (IP)= ...

  3. [汇编学习笔记][第十章 CALL和RET指令]

    第十章 CALL和RET指令 call和ret指令都是转移指令,它们都修改CS和IP.经常被共同用于实现子程序的设计.这一章,我们讲解call和ret指令的原理 10.1 ret和retf ret指令 ...

  4. call 和 ret 指令

    body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...

  5. 汇编-10.0-CALL和RET指令

    call和ret指令都是转移指令,他们都是修改IP,或同时修改CS和IP.它们常被共同用来实现子程序设计. 1.ret和retf ret指令用栈中的数据,修改IP的内容,从而实现近转移: retf指令 ...

  6. 第十章 Call 和 Ret 指令

    引言 想想程序之间的加载返回过程. call 和 ret 指令都是转移指令,它们都修改 IP,或同时修改 CS 和 IP. call 和 ret 经常被共同用来实现自程序的设计. 这一章,我们讲解 c ...

  7. 汇编语言笔记 CALL和RET指令

    转载地址:http://www.cnblogs.com/dennisOne ☞模块化程序设计 模块化程序设计 汇编语言通过call和ret指令实现了模块化程序设计.可以实现多个相互联系.功能独立的子程 ...

  8. 自己总结:汇编CALL和RET指令

    ret指令,相当于 pop IP:修改IP的内容,从而实现近转移 retf指令,相当于 pop IP pop CS:修改CS和IP的内容,从而实现远转移 -------------- CPU执行cal ...

  9. 王爽汇编第十章,call和ret指令

    目录 王爽汇编第十章,call和ret指令 call和ret指令概述: ret和retf ret指令 retf指令 call 和 ret 的配合使用 call指令详解 call原理 call指令所有写 ...

随机推荐

  1. apache tika检测文件是否损坏

    Apache Tika用于文件类型检测和从各种格式的文件内容提取的库. 将上传文件至服务器,进行解析文件时,经常需要判断文件是否损坏.我们可以使用tika来检测文件是否损坏 maven引入如下: &l ...

  2. 图论+思维(2019牛客国庆集训派对day2)

    题意:https://ac.nowcoder.com/acm/contest/1107/J n个点的完全图编号0-n-1,第i个点的权值为2^i,原先是先手选取一些边,然后后手选取一些点,满足先手选取 ...

  3. redis 命令 setbit、bitcount、getbit、bitop

    1.SETBIT key offset value 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit). 在redis中,存储的字符串都是以二级制的进行存在的. 举例: 设置一个 ke ...

  4. Hinton等人新研究:如何更好地测量神经网络表示相似性

    Hinton等人新研究:如何更好地测量神经网络表示相似性 2019年05月22日 08:39:15 喜欢打酱油的老鸟 阅读数 177更多 分类专栏: 人工智能   https://www.toutia ...

  5. 怎样通过id属性快速从HTMLCollection对象中获取到目标元素节点

    方法1: 直接使用id或name属性: 比如我想获取 id 为 img1 的图片元素节点, 则可以这样写: document.images.img1 如果没有对应节点, 则返回undefined; 方 ...

  6. BZOJ5017题解SNOI2017炸弹--玄学递推

    题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=5017 分析 老师讲课谈到了这道题,课上想出了个连边建图然后乱搞的操作,被老师钦定的递推方 ...

  7. 深入理解hadoop之HDFS

    深入理解hadoop之HDFS 刚刚才写完关于mapreduce的一篇博文,趁热打铁接下来聊聊HDFS.本博文参考资料为HADOOP权威指南第3版完版,博文如有错漏之处,敬请指正. HDFS即Hado ...

  8. Centos7:MyCat安装,配置及使用

    解压缩 使用,默认端口8066 ./mycat start //启动 ./mycat stop //停止 ./mycat restart //重启

  9. JavaScript函数式编程——柯里化

    柯里化原理 如何实现柯里化 柯里化的应用 一.柯里化原理 柯里化:在数学和计算机科学中,柯里化是一种使用多个参数的一个函数转换成一系列使用一个参数的函数的技术. 前端使用柯里化的用途主要就应该是简化代 ...

  10. PostgreSQL 初学常用实用命令

    常用命令 psql -h ip -p port -U user -d dbName 数据库 \dt(当前数据库所有表) \l(所有数据库) \c(切换数据库) \d 表名(查看表结构) table \ ...