【汇编语言】call 和 ret 指令(三) —— 深度解析汇编语言中的批量数据传递与寄存器冲突

文章目录
- 前言
- 1. 批量数据的传递
- 1.1 存在的问题
- 1.2 如何解决这个问题
- 1.3 示例演示
- 1.3.1 问题说明
- 1.3.2 程序实现
- 2. 寄存器冲突问题的引入
- 2.1 问题引入
- 2.2 分析与解决问题
- 2.2.1 字符串定义方式
- 2.2.2 分析子程序功能
- 2.2.3 得到子程序代码
- 2.3 子程序的应用
- 2.3.1 示例1
- 2.3.2 示例2
- 3. 寄存器冲突问题的发现与解决
- 3.1 重看代码
- 3.2 分析与解决问题
- 3.2.1 存在的冲突问题
- 3.2.2 解决方案的探讨
- 3.2.3 给出解决方案。
- 3.2.4 子程序的标准框架
- 3.2.5 改进之前的程序
- 结语
前言
📌
汇编语言是很多相关课程(如数据结构、操作系统、微机原理)的重要基础。但仅仅从课程的角度出发就太片面了,其实学习汇编语言可以深入理解计算机底层工作原理,提升代码效率,尤其在嵌入式系统和性能优化方面有重要作用。此外,它在逆向工程和安全领域不可或缺,帮助分析软件运行机制并增强漏洞修复能力。
本专栏的汇编语言学习章节主要是依据王爽老师的《汇编语言》来写的,和书中一样为了使学习的过程容易展开,我们采用以8086CPU为中央处理器的PC机来进行学习。
1. 批量数据的传递
1.1 存在的问题
前面学习的例程中,子程序 cube 只有一个参数,放在bx中。如果有两个参数,那么可以用两个寄存器来放,可是如果需要传递的数据有3个、4个或更多直至 N个,我们怎样存放呢?
寄存器的数量终究有限,我们不可能简单地用寄存器来存放多个需要传递的数据。对于返回值,也有同样的问题。
1.2 如何解决这个问题
在这种时候,我们将批量数据放到内存中,然后将它们所在内存空间的首地址放在寄存器中,传递给需要的子程序。对于具有批量数据的返回结果,也可用同样的方法。
接下来我们来看下具体的落实……
1.3 示例演示
1.3.1 问题说明
下面看一个例子,
设计一个子程序,功能:将一个全是字母的字符串转化为大写。
这个子程序需要知道两件事,字符串的内容和字符串的长度。
因为字符串中的字母可能很多,所以不便将整个字符串中的所有字母都直接传递给子程序。但是,可以将字符串在内存中的首地址放在寄存器中传递给子程序。因为子程序中要用到循环,我们可以用loop指令,而循环的次数恰恰就是字符串的长度。
出于方便的考虑,可以将字符串的长度放到cx。
capital: and byte ptr [si],11011111b ;将ds:si所指单元中的字母转化为大写inc si ;ds:si 指向下一个单元loop capital ret
1.3.2 程序实现
编程:将data段中的字符串转化为大写。
assume cs:codedata segmentdb 'conversation'
data endscode segmentstart: mov ax,datamov ds,axmov si,0 ;ds:si指向字符串(批量数据)所在空间的首地址mov cx,12 ;cx存放字符串的长度call capitalmov ax,4c00hint 21hcapital:and byte ptr [si],11011111binc siloop capitalretcode endsend start
❗注意:除了寄存器、内存传递参数外,还有一种通用的方法使用栈来传递参数。
2. 寄存器冲突问题的引入
2.1 问题引入
设计一个子程序:功能:将一个全是字母,以0结尾的字符串,转化为大写。
2.2 分析与解决问题
2.2.1 字符串定义方式
程序要处理的字符串以0作为结尾符,这个字符串可以如下定义:
db ‘conversation’,0
2.2.2 分析子程序功能
应用这个子程序 ,字符串的内容后面定要有一个0,标记字符串的结束。
子程序可以依次读取每个字符进行检测,如果不是0,就进行大写的转化,如果是0,就结束处理。
由于可通过检测0而知道是否己经处理完整个字符串 ,所以子程序可以不需要字符串的长度作为参数。
我们可以直接用jcxz来检测0。
2.2.3 得到子程序代码
;说明:将一个全是字母,以0结尾的字符串,转化为大写
;参数:ds:si指向字符串的首地址
;结果:没有返回值
capital:mov cl,[si]mov ch, 0jcxz ok ;如果(cx)=0,结束;如果不是0,处理and byte ptr [si], 11011111b ;将ds:si所指单元中的字母转化为大写inc si ;ds:si 指向下一个单元jmp short capitalok:ret
2.3 子程序的应用
来看一下这个子程序的应用。
2.3.1 示例1
要求:将data段中的字符串转化为大写。
assume cs:code
data segmentdb 'conversation',0
data ends
代码段中的相关程序如下。
mov ax,data
mov ds,ax
mov si,0
call capital
2.3.2 示例2
要求:将data段中字符串全部转化为大写。
assume cs:codedata segmentdb 'word', 0db 'unix', 0db 'wind', 0db 'good', 0
data ends
可以看到,所有字符串的长度都是5(算上结尾符0),使用循环,重复调用子程序capital,完成对4个字符串的处理。
完整的程序如下。
code segment
start: mov ax,datamov ds,axmov bx,0mov cx,4s: mov si,bxcall capitaladd bx,5loop smov ax,4c00hint 21hcapital:mov cl,[si]mov ch, 0jcxz okand byte ptr [si], 11011111binc sijmp short capitalok:retcode endsend start
3. 寄存器冲突问题的发现与解决
3.1 重看代码
上面的这个程序在思想上完全正确,但在细节上却有些错误,把错误找出来。
提示:问题在于cx的使用。
思考后看分析。
3.2 分析与解决问题
3.2.1 存在的冲突问题
问题在于cx的使用,主程序要使用cx记录循环次数,可是子程序中也使用了cx,在执行子程序的时候,cx中保存的循环计数值被改变,使得主程序的循环出错。
从上面的问题中,实际上引出了一个一般化的问题:子程序中使用的寄存器,很可能在主程序中也要使用,造成了寄存器使用上的冲突。
3.2.2 解决方案的探讨
那么如何来避免这种冲突呢?
粗略地看,可以有以下两个方案。
(1)在编写调用子程序的程序时,注意看看子程序中有没有用到会产生冲突的寄存器,如果有,调用者使用别的寄存器;
(2)在编写子程序的时候,不要使用会产生冲突的寄存器。
我们来分析一下上面两个方案的可行性:
(1)这将给调用子程序的程序的编写造成很大的麻烦,因为必须要小心检查所调用的子程序中是否有将产生冲突的寄存器。
比如说,在上面的例子中,我们在编写主程序的循环的时候就得检查子程序中是否用到了bx和cx,因为如果子程序中用到了这两个寄存器就会出现问题。
如果采用这种方案来解决冲突的话,那么在主程序的循环中,就不能使用cx寄存器,因为子程序中已经用到。
(2)这个方案也是不可能实现的,因为编写子程序的时候无法知道将来的调用情况。
可见,我们上面所设想的两个方案都不可行。
我们希望:
-
(1)编写调用子程序的程序的时候不必关心子程序到底使用了哪些寄存器。
-
(2)编写子程序的时候不必关心调用者使用了哪些寄存器。
-
(3)不会发生寄存器冲突。
3.2.3 给出解决方案。
解决这个问题的简捷方法是,在子程序的开始将子程序中所有用到的寄存器中的内容都保存起来,在子程序返回前再恢复。可以用栈来保存寄存器中的内容。
3.2.4 子程序的标准框架
以后,我们编写子程序的标准框架如下:

3.2.5 改进之前的程序
我们改进一下子程序 capital的设计:
capital: push cxpush sichange: mov cl,[si]mov ch, 0jcxz okand byte ptr [si], 11011111binc sijmp short capitalok: pop sipop cxret
要注意寄存器入栈和出栈的顺序。
结语
今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下。
也可以点点关注,避免以后找不到我哦!
Crossoads主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是作者前进的动力!

相关文章:
【汇编语言】call 和 ret 指令(三) —— 深度解析汇编语言中的批量数据传递与寄存器冲突
文章目录 前言1. 批量数据的传递1.1 存在的问题1.2 如何解决这个问题1.3 示例演示1.3.1 问题说明1.3.2 程序实现 2. 寄存器冲突问题的引入2.1 问题引入2.2 分析与解决问题2.2.1 字符串定义方式2.2.2 分析子程序功能2.2.3 得到子程序代码 2.3 子程序的应用2.3.1 示例12.3.2 示例…...
定义函数合并字符串—超详细讲解
【问题描述】 编写一个函数void str_bin(char str1[ ], char str2[ ]), str1、str2是两个有序字符串(其中字符按ASCII码从小到大排序),将str2合并到字符串str1中,要求合并后的字符串仍是有序的,允许字符重…...
实现 vue3 正整数输入框组件
1.实现代码 components/InputInteger.vue <!-- 正整数输入框 --> <template><el-input v-model"_value" input"onInput" maxlength"9" clearable /> </template><script lang"ts" setup> import { ref …...
Leetcode - 周赛425
目录 一,3364. 最小正和子数组 二, 3365. 重排子字符串以形成目标字符串 三,3366. 最小数组和 四,3367. 移除边之后的权重最大和 一,3364. 最小正和子数组 本题可以直接暴力枚举,代码如下: …...
c++(斗罗大陆2)
我把魂力等级更新到了31级 #include<iostream> #include<conio.h> #include<windows.h> #include<stdlib.h> #include<stdio.h> #include<time.h> #include<string.h> using namespace std; int qs10; int xthl0;//先…...
redis常见数据类型
Redis是一个开源的、内存中的数据结构存储系统,它可以用作数据库、缓存和消息代理,支持多种数据类型。 一、数据类型介绍 String(字符串) Redis中最基本的数据类型。可以存储任何类型的数据,包括字符串、数字和二进制…...
MySQL - 性能优化
使用 Explain 进行分析 Explain 用来分析 SELECT 查询语句,开发人员可以通过分析 Explain 结果来优化查询语句。 比较重要的字段有: select_type : 查询类型,有简单查询、联合查询、子查询等 key : 使用的索引 rows : 扫描的行数 type :…...
Linux进程概念-详细版(一)
目录 进程概念 描述进程-PCB task_struct-PCB的一种 task_struct内容分类 查看进程 通过系统目录查看 通过ps命令查看 通过系统调用获取进程的PID和PPID 通过系统调用创建进程 fork的认识 使用if进行分流 最后的总结 Linux进程状态 运行状态-R 浅度睡眠状态-S 深度睡…...
K8S网络系列--Flannel网络下UDP、VXLAN模式的通信流程机制分析
文章目录 前言一、了解overlay、underlay容器网络二、网络通信1.分类2.网络虚拟设备对2.1、什么是网络虚拟设备对veth pair?2.2、如何查看容器的网卡与主机的哪个veth设备对是成对的关系? 3、vxlan和vtep3.1、vtep3.2、vxlan相关概念 三、Flannel网络模式剖析0、flannel的作用…...
ThreadLocal的设计思考
问题的提出 在Java多线程中,共享变量的读写非常容易出现不可预测的行为,因此对共享变量的访问控制非常重要。因此在多线程编程时,为了保证线程安全,需要进行额外的同步措施。比如典型的操作就是加锁。除了加锁外,另一…...
shell脚本练习(2)
1. 使用case实现成绩优良差的判断 2. for创建20用户 用户前缀由用户输入 用户初始密码由用户输入 例如:test01,test10 3. for ping测试指网段的主机 网段由用户输入,例如用户输入192.168.2 ,则ping 192.168.2.10 --- 192.168.2.2…...
通讯专题4.1——CAN通信之计算机网络与现场总线
从通讯专题4开始,来学习CAN总线的内容。 为了更好的学习CAN,先从计算机网络与现场总线开始了解。 1 计算机网络体系的结构 在我们生活当中,有许多的网络,如交通网(铁路、公路等)、通信网(电信、…...
Harmony NEXT-越过相机读写权限上传图片至项目云存储中
问题成因 在制作用户注册登录界面时想要实现用户头像上传共能,查询API文档,发现有picker和PhotoAccessHelper两个包可以选择使用,但是在使用PhotoAccessHelper包拉起相册并读入所选的照片后将该照片传入云存储中产生报错,需要相册…...
MATLAB基础应用精讲-【数模应用】Retinex图像去雾算法(附MATLAB和python代码实现)
目录 前言 算法原理 图像去雾 数学模型 算法步骤 算法拓展 多尺度Retinex (MSR) 算法 MSR算法的实现细节 McCann Retinex 算法 McCann99 Retinex算法 基于暗通道先验的图像去雾算法 暴力解法——直方图均衡化去雾 基于Retinex理论的图像去雾 基于暗通道先验的单…...
点击A组件跳转到B页面的tab的某一列
1、使用vuex存储点击的数据; 点击A组件里面的button按钮: <div><button click"banli(first)">已办理</button><button click"banli(second)">未办理</button><button click"banli(third)&quo…...
HarmonyOS xml转换JavaScript 常用的几个方法
HarmonyOS 使用 xml转换JavaScript 的好处 易用性: 提供了简洁的API接口,使得XML到JavaScript对象的转换变得简单直接。转换选项的灵活性允许开发者根据实际需求自定义转换结果。 高效性: HarmonyOS对底层运行时环境进行了优化,使…...
Linux笔记---进程:进程等待
1. 进程等待的概念 进程等待是指父进程通过系统调用wait或waitpid来对子进程进行状态检测与回收的功能。 当子进程退出时,如果父进程不读取子进程的退出状态,子进程就会成为僵尸进程,造成内存泄漏的问题。因此,父进程需要调用wa…...
【Linux】匿名管道通信场景——进程池
🔥 个人主页:大耳朵土土垚 🔥 所属专栏:Linux系统编程 这里将会不定期更新有关Linux的内容,欢迎大家点赞,收藏,评论🥳🥳🎉🎉🎉 文章目…...
算法妙妙屋-------1.递归的深邃回响:全排列的奇妙组合
全排列的简要总结 全排列(Permutation)是数学中一个经典的问题,指的是从一组元素中,将所有元素按任意顺序排列形成的所有可能序列。 特点 输入条件: 给定一组互异的元素(通常为数组或字符串)。…...
【maven-6】Maven 生命周期相关命令演示
Maven 是一个广泛使用的项目管理工具,尤其在 Java 项目中。它通过定义一系列的生命周期阶段(Phases)来管理项目的构建过程。理解这些生命周期阶段及其相关命令,对于高效地构建和管理项目至关重要。本文将通过实际演示,…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
LangFlow技术架构分析
🔧 LangFlow 的可视化技术栈 前端节点编辑器 底层框架:基于 (一个现代化的 React 节点绘图库) 功能: 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...
深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏
一、引言 在深度学习中,我们训练出的神经网络往往非常庞大(比如像 ResNet、YOLOv8、Vision Transformer),虽然精度很高,但“太重”了,运行起来很慢,占用内存大,不适合部署到手机、摄…...
华为OD最新机试真题-数组组成的最小数字-OD统一考试(B卷)
题目描述 给定一个整型数组,请从该数组中选择3个元素 组成最小数字并输出 (如果数组长度小于3,则选择数组中所有元素来组成最小数字)。 输入描述 行用半角逗号分割的字符串记录的整型数组,0<数组长度<= 100,0<整数的取值范围<= 10000。 输出描述 由3个元素组成…...
消防一体化安全管控平台:构建消防“一张图”和APP统一管理
在城市的某个角落,一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延,滚滚浓烟弥漫开来,周围群众的生命财产安全受到严重威胁。就在这千钧一发之际,消防救援队伍迅速行动,而豪越科技消防一体化安全管控平台构建的消防“…...
