汇编语言——第10章 CALL和RET指令

这篇具有很好参考价值的文章主要介绍了汇编语言——第10章 CALL和RET指令。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

引言

10.1 ret和retf

检测点10.1

10.2 call指令

10.3 依据位移进行转移的call指令

检测点10.2 

10.4 转移的目的地址在指令中的call指令

检测点10.3 

10.5 转移地址在寄存器中的call指令

检测点10.4 

10.6 转移地址在内存中的call指令

检测点 10.5

10.7 call和ret的配合使用

10.8 mul指令

10.9 模块化程序设计

10.10 参数和结果传递的问题

10.11 批量数据的传递

10.12 寄存器冲突的问题


引言

call和ret指令都是转移指令,他们都修改IP,或同时修改CS和IP。

它们经常被共同用来实现子程序的设计。

10.1 ret和retf

ret指令用栈中的数据来修改IP的内容,从而实现近转移。

CPU执行ret指令时:

1(IP)=((ss)*16+(sp)),指向栈顶

2(sp)=(sp)+2

retf指令用栈中的数据,修改CSIP的内容,从而实现远转移。

CPU执行retf指令时:

1(IP)=((ss)*16+(sp))

2(sp)=(sp)+2

3(CS)=((ss)*16+(sp))

4(sp)=(sp)+2

用汇编的语法来解释retretf指令:

CPU执行ret指令相当于进行:pop IP

CPU执行retf指令相当于进行:pop IPpop CS

assume cs:code

 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 ax

              mov bx,0

              ret

code ends

end start文章来源地址https://www.toymoban.com/news/detail-414899.html

ret指令执行后,(IP)=0,CS:IP指向代码段的第一条命令。

assume cs:code

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

              mov bx,0

              retf

codesg ends

end start

 retf指令执行后,CS:IP指向代码段的第一条命令。

检测点10.1

汇编语言——第10章 CALL和RET指令

10.2 call指令

call指令经常跟ret指令配合使用,CPU执行call指令时:

1、将当前的IP或者CS和IP压入栈;

2、转移(jmp)。

call指令除了不能实现短转移之外,call指令实现转移的方法和jmp指令的原理相同。

call指令实现段间的转移(远转移)或近转移。

10.3 依据位移进行转移的call指令

call标号(将当前的IP压入栈后转到目标处执行指令)

call执行此种格式的call指令时,进行以下操作:

(1)(SP)=(SP)-2
      ((SS)*16+(SP))=(IP)

(2)(IP)=(IP)+16位位移;

16位位移=标号处的地址-call指令后的第一个字节的地址。

16位位移的范围是-32768~32767,用补码表示。

16位位移由编译程序在编译时算出。

用汇编语法解释call指令:

push IP

jmp near ptr 标号

检测点10.2 

汇编语言——第10章 CALL和RET指令

10.4 转移的目的地址在指令中的call指令

“call far ptr 标号”实现的是段间转移。

call执行此种格式的call指令时,进行以下操作:

(1)(sp)=(sp)-2

           ((ss)*16+(sp))=(CS)

         (sp)=(sp)-2

           ((ss)*16+(sp))=(IP)

(2)(CS)=标号所在段的段地址

       (IP)=标号所在段的偏移地址

用汇编语法解释call指令:

push CS

push IP

jmp far ptr 标号 

检测点10.3 

汇编语言——第10章 CALL和RET指令

10.5 转移地址在寄存器中的call指令

指令格式是:call 16位reg

功能:

(1)(sp)=(sp)-2

(2)((ss)*16+(sp))=(IP)

(3)(IP)=(16位reg)

用汇编语法解释此种call指令,CPU执行“call 16reg”时,相当于:

push IP

jmp 16位reg

检测点10.4 

汇编语言——第10章 CALL和RET指令

10.6 转移地址在内存中的call指令

 转移地址在内存中的call指令有两种格式:

(1)call word ptr 内存单元地址;段内跳转

用汇编语法解释call word ptr 内存单元地址:

       push IP

       jmp word ptr 内存单元地址

例子:

mov sp,10h

mov ax,0123H

mov ds:[0],ax

call word ptr ds:[0]

执行后,(IP)=0123H,(sp)=0EH.

(2) call dword ptr 内存单元地址;段间跳转

         用汇编语法解释call dword ptr 内存单元地址

       push CS

       push IP

       jmp word 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。 

检测点 10.5

汇编语言——第10章 CALL和RET指令

10.7 call和ret的配合使用

10.8 mul指令

mul是乘法指令,使用mul做乘法的时候应注意以下两点:

(1)两个相乘的数:两个相乘的数,要么都是8位,要么都是16位。如果是8位,一个默认放在AL中,另一个放在8位reg或内存字节单元中;如果是16位,一个默认在AX中,另一个放在16位reg或内存字单元中。

(2)结果:如果是8位乘法,结果默认放在AX中;如果是16位乘法,结果高位默认在DX中存放,低位在AX中存放。

格式:

mull reg

mull 内存单元

内存单元可以用不同的寻址方式给出,比如:

mull byte ptr ds:[0]

含义:(ax)=(al)*((ds)*16+0);

mull word ptr [bx+si+idata]

含义:(ax)=(ax)*((ds)*16+(bx)+(si)+idata)结果的低6位。

  (dx)=(ax)*((ds)*16+(bx)+(si)+idata)结果的高6位。

例子: 

 (1)计算100*10

两个数都小于255,可以做8位乘法 

mov al,100

mov bl,10

mul bl

结果(ax)=1000(03E8H)

(2)计算100*1000

1000都大于255,要做16位乘法

mov ax,100

mov bx,10000

mul bx

结果(ax)=4240H(dx)=000FH,(F4240H=1000000)

10.9 模块化程序设计

calret指令共同支持汇编语言编程中的模块化设计。

10.10 参数和结果传递的问题

用寄存器来存储参数和结果是最常用的方法。对于存放参数的寄存器和存放结果的寄存器,调用者和子程序的读写操作恰恰相反:

调用者将参数送入参数寄存器,从结果寄存器中取到返回值;

子程序从参数寄存器中取到参数,将返回值送入结果寄存器。

编程:计算data段中第一组数据的3次方,结果保存在后面一组dword单元中

assume cs:code

 data segment

     dw 1,2,3,4,5,6,7,8

     dd 8 dup (0)

 data ends

code segment

   start:   mov ax,data

              mov ds,ax

              mov si,0                               ;ds:si指向第一组word单元

              mov di,16                             ;ds:di指向第二组dword单元

              mov cx,8

          s: mov bx,[si]

              call cube

              mov [di],ax

              mov [di].2,dx

              add si,2                                ;ds:di指向下一个word单元

              add di,4                                ;ds:di指向下一个dword单元

              loop s

              mov ax,4c00h

              int 21h

    cube: mov ax,bx

              mul bx

              mul bx

              ret

code ends

end start

10.11 批量数据的传递

将批量数据放在内存中,然后将它们所在内存空间的首地址放在寄存器中,传递给需要的子程序,批量数据的返回结果也是采用同样的方法。除此之外还可以用栈来传递参数。

编程:将data段中的字符串转化为大写

assume cs:code

data segment

    db 'conversation'

data ends

code segment

    start: mov ax,data

             mov ds,ax

             mov si,0                ;ds:si指向字符串(批量数据)所在空间的首地址

             mov cx,12             ;cx存放字符串的长度

             call capital

             mov ax,4c00h

             int 21h

capital: add byte ptr [si],11011111B

             inc si

             loop capital

             ret

code ends

end start

10.12 寄存器冲突的问题

编程:将一个全是字母,以0结尾的字符串转化为大写

capital: mov cl,[si]                               ;8

            mov ch,0                                 ;8位设置为0

            jcxz ok                                     ;如果(cx)=0则结束,如果不是0则处理

            and byte ptr [si],11011111B

            inc si

            jmp short capital

       ok: ret

编程:将data段中的字符串全部转化为大写

assume cs:code

data segment

    db  'word',0

    db  'unix',0

    db  'wind',0

    db  'good',0

data ends

此程序有bugcx有问题

assume cs:code

data segment

    db  'word',0

    db  'unix',0

    db  'wind',0

    db  'good',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: mov cl,[si]

              mov ch,0

              jcxz ok

              and byte ptr [si],11011111b

              inc si

              jmp short capital

        ok: ret

code ends

end start

到了这里,关于汇编语言——第10章 CALL和RET指令的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C语言代码的x86-64汇编指令分析过程记录

    先通过Xcode创建一个terminal APP,语言选择C。代码如下: 在return 0处打上断点,并且Xcode菜单里选择Debug|Debug Workflow|Always Show Disassembly,点击运行。这时候断点会跳到汇编代码里,得到汇编代码如下: 首先介绍下面会用到的几个寄存器: rip : 程序计数寄存器 rsp : 栈指针寄存器

    2024年02月14日
    浏览(27)
  • 用ARM进行汇编语言编程(4)带有分支的循环和条件指令执行

    ARM 编程模拟器网站地址: 在arm里也有和高级语言一样的for和while循环,可以根据条件来判断是否执行 首先我们创建一个data标签,然后在里面写一个分支,存放一些数值,然后使这些存放的数值依次相加 然后我们要将list加载到内存里 然后使用直接寻址,将r0寄存器里的值放

    2024年02月06日
    浏览(37)
  • 汇编语言实验8:BIOS/DOS功能调用与宏指令程序设计

    掌握汇编语言程序设计的基本方法和技能 掌握汇编语言源程序的编辑汇编连接和执行的完整过程 通过上机操作理解宏定义、宏调用、宏展开的概念,熟练运用宏功能编写程序 掌握BIOS/DOS基础功能的实现调用方法 理解常用的DOS功能调用的基本使用,能熟练运用1号,2号,9号,

    2024年02月03日
    浏览(52)
  • 《汇编语言》王爽(第四版) 第十章 实验10

    文章目录 前言 一、子程序1 显示字符串 1.实验任务 2.分析 (1)如何在指定位置显示 (2)如何显示指定颜色 (3)保存子程序中用到的寄存器 3.代码 二、子程序2 解决除法溢出的问题 1.实验任务 2.代码 三、子程序3 数值显示 1.实验任务 2.显示一个word型数据的代码 总结 本文是

    2024年02月08日
    浏览(30)
  • call指令和ret指令【笔记+详解】

       在高级语言中,常有主程序调用其他子程序,子程序还可以调用子程序…,比如在C语言中,在main主函数里调用cube函数,该函数被执行完后返回main函数,然后程序继续往下执行,如下:   在汇编语言中也有类似的这种机制,能实现主程序调用子程序。这就要使用cal

    2024年02月03日
    浏览(30)
  • 【ARM64 常见汇编指令学习 21 -- ARM RET 与 ERET】

    请阅读 【嵌入式开发学习必备专栏 】 在 ARMv8 架构中, RET 指令用于从函数或者过程返回。它主要负责从当前过程跳转回调用者,并恢复调用者的程序计数器 (PC) 的值。 语法: Xn 是一个可选的寄存器,通常为 X30 (也称为 LR ,链接寄存器),其中包含返回地址。如果没有指

    2024年04月10日
    浏览(73)
  • 汇编语言笔记(一)——汇编语言基础

    一、开发环境 我使用visual studio 2022 preview,其他版本的设置大同小异。 第一步: 打开visual studio,点击“创建新项目”: 第二步: visual studio并没有专门的汇编项目,所以需要挂羊头卖狗肉,选择C++空项目 第三步: 输入项目名称,点击创建 第四步: 鼠标右键单击项目名称—

    2024年02月05日
    浏览(30)
  • 5.6 汇编语言:汇编高效数组寻址

    数组和指针都是用来处理内存地址的操作,二者在C语言中可以互换使用。数组是相同数据类型的一组集合,这些数据在内存中是连续存储的,在C语言中可以定义一维、二维、甚至多维数组。多维数组在内存中也是连续存储的,只是数据的组织方式不同。在汇编语言中,实现

    2024年02月11日
    浏览(32)
  • 5.8 汇编语言:汇编高效除法运算

    通常情况下计算除法会使用 div/idiv 这两条指令,该指令分别用于计算无符号和有符号除法运算,但除法运算所需要耗费的时间非常多,大概需要比乘法运算多消耗10倍的CPU时钟,在Debug模式下,除法运算不会被优化,但Release模式下,除法运算指令会被特定的算法经过优化后转

    2024年02月11日
    浏览(33)
  • 5.7 汇编语言:汇编高效乘法运算

    乘法指令是一种在CPU中实现的基本算术操作,用于计算两个数的乘积。在汇编语言中,乘法指令通常是通过 mul(无符号乘法) 和 imul(有符号乘法) 这两个指令实现的。由于乘法指令在执行时所消耗的时钟周期较多,所以编译器在优化代码时通常会尝试将乘法操作转换为更

    2024年02月11日
    浏览(21)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包