《汇编语言》- 读书笔记 - 第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.6 转移地址在内存中的 call 指令
    • 检测点 10.5
  • 10.7 call 和 ret 的配合使用
    • 问题 10.1
  • 10.8 mul 指令
    • 例1. 计算 100*10
    • 例2. 计算 100*10000
  • 10.9 模块化程序设计
  • 10.10 参数和结果传递的问题
  • 10.11 批量数据的传递
  • 10.12 寄存器冲突的问题
    • 问题举例:
    • 解决思路:
    • 子程序的标准框架
      • 改进后的子程序 capital
  • 实验 10 编写子程序

callret 指令都是转移指令,都有修改 IPCS:IP两个版本。
callret 指令共同支撑了汇编语言中的 模块化设计实现。
call 指令用于 调用子程序,它将 返回地址压入 堆栈并跳转至 子程序入口地址。
ret 指令在 子程序执行 完毕后从 堆栈中弹出 返回地址,并跳转回 主程序调用点继续执行。

10.1 ret 和 retf

指令修改CS修改IP行为用途
ret
(Return from Procedure)
POP IP:将栈顶的值弹出,并送进IP从子程序返回。
retf
(Return from Procedure Far)
POP IP将栈顶的值弹出,送进IP
POP CS将从栈中弹出一个值,送进CS
从远过程(far subroutine)返回

检测点 10.1

《汇编语言》- 读书笔记 - 各章检测点归档 - 检测点 10.1

10.2 call 指令

CPU 执行 call 指令时,进行两步操作:

  1. 将当前的 IPCSIP 压入栈中;
  2. 转移。(与 jmp 唯一的不同在于没有短转移 : jmp short 标号 )
命令说明修改的
寄存器
例子(假设有标号叫 label
call 标号位移跳转,实现段内转移。位移范围在:-32768 ~ 32767
将当前IP压栈后,转到标号处执行指令。相当于:
1. push IP
2.jmp near ptr 标号
IPcall label
call far ptr 标号目标地址,实现段间转移。相当于:
1. push CS
2. push IP
3.jmp far ptr 标号
CS:IPcall far ptr label
call 16位寄存器转移地址在寄存器中,相当于:
1. push IP
2.jmp 16位寄存器
IPcall ax
call word ptr [内存]转移地址在内存中,实现段内转移。相当于:
1. push IP
2.jmp word ptr 内存单元地址
IPcall word ptr ds:[0]
call dword ptr [内存]转移地址在内存中,实现段间转移。相当于:
1. push CS
2. push IP
3.jmp dword ptr 内存单元地址
IPcall dword ptr ds:[0]

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

检测点 10.2

《汇编语言》- 读书笔记 - 各章检测点归档 - 检测点 10.2

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

检测点 10.3

《汇编语言》- 读书笔记 - 各章检测点归档 - 检测点 10.3

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

## 检测点 10.4
《汇编语言》- 读书笔记 - 各章检测点归档 - 检测点 10.4

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

检测点 10.5

《汇编语言》- 读书笔记 - 各章检测点归档 - 检测点 10.5

10.7 call 和 ret 的配合使用

问题 10.1

下面程序返回前,bx 中的值是多少?

assume cs:code 
code segment
start:	mov ax,1mov cx,3call smov bx,ax		;(bx)=?mov ax,4c00hint 21h
s:		add ax,axloop sret
code ends
end start
  1. call s 会将当前 IP 存入栈中,跳到 s 处执行。
  2. s 标号这里是一个 loop 循环 cx 初始为 3 所以会循环 3 次。
    2.1. 第一次 add ax, ax, ax = 1+1 = 2;
    2.2. 第二次 add ax, ax, ax = 2+2 = 4;
    2.3. 第三次 add ax, ax, ax = 4+4 = 8;
  3. loop 循环结束后 ret 返回 call s 处,继续执行它下面的指令。此时 ax = 8
    sret这段实现的是计算2n 次方,ncx 提供。
  4. 所以 mov bx, ax 的结果是 bx = 8
  5. 下一句 mov ax,4c00h 退出程序,最终程序返回前 bx 中的值是 8

通过对问题 10.1的探讨,引出:利用 callret 来实现子程序的机制。
子程序的框架如下:

标号:指令ret

具有子程序的源程序的框架如下:
在这里插入图片描述

10.8 mul 指令

mul 是乘法指令。两个相乘的数,要么都是8位,要么都是 16 位

  1. 乘数:可以是816位。
    1.1. 但两个乘数必须都是 8位,或都是16位。(不能一8位,一个16位)
    1.2. 如果是8位乘法:一个乘数默认在 AL 中,另一个在8位寄存器内存【字节】单元中。
    1.3. 如果是16位乘法:一个乘数默认在 AX 中,另一个在16位寄存器内存【字】单元中。

  2. 结果
    2.1. 8位乘法:结果在AX
    2.2. 16位乘法:结果高16位DX低16位AX

乘法位数乘数A乘数B结果例子
8位乘法ALah | bl | bh | cl
| ch | dl | dh | [字节单元]
AXmul bl
mul byte ptr ds:[0]
16位乘法AXbx | cx | dx | [字单元]DX AXmul bx
mul word ptr [bx+si+8]

例1. 计算 100*10

assume cs:code 
code segment
start:	mov al,100mov bl,10mul bl
code ends
end start

在这里插入图片描述

parseInt('03E8', 16); // 1000

例2. 计算 100*10000

assume cs:code 
code segment
start:	mov ax,100mov bx,10000mul bx
code ends
end start

在这里插入图片描述

parseInt('F4240', 16); // 1000_000

10.9 模块化程序设计

  1. 模块化设计在汇编语言中至关重要,通过拆解复杂问题为相互关联的子问题
  2. callret 指令支持模块化编程,分别用于调用返回子程序。
  3. 子程序利用这两指令实现功能独立逻辑分离,便于解决复杂问题。

总之,callret 提供了实现子程序的基础,以解决复杂的编程问题。什么提高代码可读性、可维护性和复用性,布啦布啦布啦。。。

10.10 参数和结果传递的问题

  1. 在设计函数经常要考虑的就是怎么传参、怎么返回值。
    1.2. 优先使用寄存器,比较方便。寄存器不够用,就使用内存。
  2. 注释要写清楚。起码以后自己要能看懂(不要高估和曾经那个自己之间的默契)

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

assume cs:code 
data segmentdw 1,2,3,4,5,6,7,8dd 0,0,0,0,0,0,0,0
data endscode segment
start:	mov ax,data		; 设置数据段mov ds,axmov si,0		;ds:si 指向第一组 word 单元mov di,16		;ds:di 指向第二组 dword 单元mov cx,8		; 设置循环次数 8s:	mov bx,[si]		; 主程序,读取数据到 bx ("用 bx 传参")call cubemov [di],ax		; 先存低16"主程序拿到子程序放在 ax 中的返回值"mov [di].2,dx	; 再存高16"主程序拿到子程序放在 dx 中的返回值"add si,2		;ds:si 指向下一个 word 单元add di,4		;ds:di 指向下一个 dword 单元loop smov ax,4c00hint 21h; cube 子程序:计算 n 的 3 次方cube:	mov ax,bx		; 子程序从("bx 读取传参")mul bxmul bxret				; 子程序返回 "(返回值)""ax,dx" 中
code ends
end start

在这里插入图片描述

计算 3 次方的数12345678
内存中结果
低位在前,高位在后
(高16位都是0忽略)
01 0008 001B 0040 007D 00D8 0057 0100 02
调整一下顺序00010008001B0040007D00D8015702 00
转成10进制182764125216343512

10.11 批量数据的传递

数据大了就需要用内存传参返回了。
寄存器用来传递内存地址。

assume cs:code 
data segmentdb 'conversation'
data endscode segment
start:	mov ax,data		; 设置数据段mov ds,axmov si,0		; ds:si 指向字符串(批量数据)所在空间的首地址mov cx,12		; cx存放字符串的长度call capital	; 调用子程序mov ax,4c00hint 21h; 子程序:转大写
capital:and byte ptr [si],11011111b ; 转为大写字符inc siloop capital				; 循环处理字符ret
code ends
end start

在这里插入图片描述

10.12 寄存器冲突的问题

本节用一个子程序 举例,在主程序子程序使用了同样的寄存器,那么将产生冲突。

问题举例:

  1. 首先:主程序在 CX 中保存了循环次数。
  2. 然后:子程序中的循环计数也用到了CX
  3. 结果:当从子程序返回主程序时,主程序的循环计数已经丢失。程序无法按预期执行。

解决思路:

  1. 子程序具体业务代码开始前,把会用到的寄存器保存到中。
  2. 子程序返回前出栈还原寄存器
  3. 注意入栈出栈时的顺序。(后入的先出)

子程序的标准框架

最终得出编写子程序的标准框架如下:

子程序开始:	子程序中使用的寄存器入栈子程序内容子程序中使用的寄存器出栈返回(ret、retf)

改进后的子程序 capital

capital:push cxpush sichange:mov cl,[si]mov ch,0jcxz okand byte ptr [si],11011111binc sijmp short changeok:pop sipop cxret

关于大小写的相关知识,详见:第7章 7.4 大小写转换的问题

实验 10 编写子程序

《汇编语言》- 读书笔记 - 实验 10 编写子程序

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/478335.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

调用接口时不时出现 Error: socket hang up

项目场景: 提示:这里简述项目相关背景: 今天采用golang创建了一个http服务,准备对若干接口进行测试。 问题描述 提示:这里描述项目中遇到的问题: 在测试第一个接口时,发现采用postman调用接口…

多维时序 | Matlab实现LSTM-Mutilhead-Attention长短期记忆神经网络融合多头注意力机制多变量时间序列预测模型

多维时序 | Matlab实现LSTM-Mutilhead-Attention长短期记忆神经网络融合多头注意力机制多变量时间序列预测模型 目录 多维时序 | Matlab实现LSTM-Mutilhead-Attention长短期记忆神经网络融合多头注意力机制多变量时间序列预测模型预测效果基本介绍程序设计参考资料 预测效果 基…

通俗易懂的L0范数和L1范数及其Python实现

定义 L0 范数(L0-Norm) L0 范数并不是真正意义上的一个范数,因为它不满足范数的三角不等式性质,但它在数学优化和信号处理等领域有着实际的应用。L0 范数指的是向量中非零元素的个数。它通常用来度量向量的稀疏性。数学上表示为…

rocketMQ-Dashboard安装与部署

1、下载最新版本rocketMQ-Dashboard 下载地址:https://github.com/apache/rocketmq-dashboard 2、下载后解压,并用idea打开 3、修改配置 ①、修改端口及rocketmq服务的ip:port ②、修改访问账号、密码 3、然后启动访问: 4、mav…

LabVIEW高速信号测量与存储

LabVIEW高速信号测量与存储 介绍了LabVIEW开发的高速信号测量与存储系统,解决实验研究中信号捕获的速度和准确性问题。通过高效的数据处理和存储解决方案,本系统为用户提供了一种快速、可靠的信号测量方法。 项目背景 在科学研究和工业应用中&#xf…

透彻理解实时数仓的支撑技术:Upsert Kafka 和 Flink 动态表(Dynamic Table)

博主历时三年精心创作的《大数据平台架构与原型实现:数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行,点击《重磅推荐:建大数据平台太难了!给我发个工程原型吧!》了解图书详情,…

【wails】(1):使用go做桌面应用开发,wails框架入门学习,在Linux上搭建环境,运行demo项目,并打包测试

1,视频地址 https://www.bilibili.com/video/BV1fK421b7QC/ 【wails】(1):使用go做桌面应用开发,wails框架入门学习,在Linux上搭建环境,运行demo项目,并打包测试 2,参考…

力扣(LeetCode)数据结构练习题(2)

今天又写了两道关于链表的练习题,来给大家分享一下。巩固一下上一篇学到的链表知识,题目可以然我们更清楚的认识链表。 目录 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表 给你单链表的头结点 head ,请…

看小姐姐的效果棒极了,写了一个工具,逐帧解析视频转成图片,有没有带上商业思维的小伙伴一起研究下

一个突然的想法,促成了这个项目雏形。 原理是: 上传一个视频,自动将视频每一帧保存成图片 然后前端访问 就能实现如图效果 后端是python/flask 数据库mysql 前端uniapp 项目演示: xt.iiar.cn 后端代码如下: #学习…

数据分析 - 机器学习

1:线性回归 线性回归是一种统计技术用于对输出变量与一个或多个输入变量之间的关系进行建模 用外行人的话来说,将其视为通过某些数据点拟合一条线,如下所示 以便在未知数据上进行预测,假设变量之间存在线性关系 点和线之间存在微小…

普中51单片机学习(十一)

独立按键 独立按键原理 按键在闭合和断开时触电存在抖动现象 硬件消抖电路如下 实验代码 #include "reg52.h" typedef unsigned char u8; typedef unsigned int u16;void delay(u16 i) {while(i--); } sbit ledP2^0; sbit k1P3^1;void keypro() {if(k10){delay(1…

五步解决 Ubuntu 18.04 出现GLIBC_2.28 not found的解决方法

Ubuntu 18.04 出现GLIBC_2.28 not found的解决方法 参考debian网址https://packages.debian.org/buster/并搜索想要的软件或者工具等,如libc6,有结果如下: 具体就不介绍了,请浏览官网了解。 第一步:添加软件源,在/et…