【汇编语言】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主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是作者前进的动力!

在这里插入图片描述

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

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

相关文章

前端的面试题

1.常用的块与行属性内标签有哪些?有什么特征? 块标签:div、h1~h6、ul、li、table、p、br、form。 特征:独占一行,换行显示,可以设置宽高,可以嵌套块和行 行标签:span、a、img、text…

48-基于单片机的LCD12864时间调控和串口抱站

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机的公交报站系统,可以手动报站,站名十个。 在lcd12864上显示时间(年月日时分秒)和站名,时间可以设置, 仿真中可以…

如何为 XFS 文件系统的 /dev/centos/root 增加 800G 空间

如何为 XFS 文件系统的 /dev/centos/root 增加 800G 空间 一、前言二、准备工作三、扩展逻辑卷1. 检查现有 LVM 配置2. 扩展物理卷3. 扩展卷组4. 扩展逻辑卷四、调整文件系统大小1. 检查文件系统状态2. 扩展文件系统五、处理可能出现的问题1. 文件系统无法扩展2. 磁盘空间不足3…

Redis 分布式锁实现方案

一、概述 分布式锁,即分布式系统中的锁。在单体应用中我们通过锁解决的是控制共享资源访问的问题,而分布式锁,就是解决了分布式系统中控制共享资源访问的问题。与单体应用不同的是,分布式系统中竞争共享资源的最小粒度从线程升级…

前端node.js

一.什么是node.js 官网解释:Node.js 是一个开源的、跨平台的 JavaScript 运行时环境。 二.初步使用node.js 需要区分开的是node.js和javascript互通的只有console和定时器两个API. 三.Buffer Buffer 是一个类似于数组的 对象,用于表示固定长度的字节序列。Buffer…

构造函数与析构函数错题汇总

构造函数不能定义返回类型,也没有返回类型。 堆、栈、静态存储区。栈上的对象main函数结束就释放,堆上的需要手动释放,静态存储区的在所在作用域的程序结束时释放。这里static在main函数内,是局部变量,所以作用域为…

SQL基础入门——SQL基础语法

1. 数据库、表、列的创建与管理 在SQL中,数据库是一个数据的集合,包含了多个表、视图、索引、存储过程等对象。每个表由若干列(字段)组成,表中的数据行代表记录。管理数据库和表的结构是SQL的基础操作。 1.1 创建数据…

亚马逊自研大语言模型 Olympus 即将亮相,或将在 LLM 竞赛中掀起新波澜

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…

自然语言处理期末试题汇总

建议自己做,写完再来对答案。答案可能存在极小部分错误,不保证一定正确。 一、选择题 1-10、C A D B D B C D A A 11-20、A A A C A B D B B A 21-30、B C C D D A C A C B 31-40、B B B C D A B B A A 41-50、B D B C A B B B B C 51-60、A D D …

深度学习——激活函数

一、人工神经元 1.1 构建人工神经元 人工神经元接受多个输入信息,对它们进行加权求和,再经过激活函数处理,最后将这个结果输出。 1.2 组成部分 输入(Inputs): 代表输入数据,通常用向量表示,每…

新型大语言模型的预训练与后训练范式,Meta的Llama 3.1语言模型

前言:大型语言模型(LLMs)的发展历程可以说是非常长,从早期的GPT模型一路走到了今天这些复杂的、公开权重的大型语言模型。最初,LLM的训练过程只关注预训练,但后来逐步扩展到了包括预训练和后训练在内的完整…

[js] 函数柯里化

面试题:实现一个add方法,使计算结果能够满足如下预期: add(1)(2)(3) 6; add(1, 2, 3)(4) 10; add(1)(2)(3)(4)(5) 15; // 保存不定长参数 let nums []; function add(...args) { // 往数组中插入不定长参数nums.push(...args)// 判断参数…

git rebase-优雅合并与修改提交

文章目录 简介rebase用于合并使用rebase修改提交cherry-pick 简介 在Git核心概念图例与最常用内容操作(reset、diff、restore、stash、reflog、cherry-pick)中我们已经介绍了git的最常用实用的命令。 在上面说的那篇文章中,我们只是简单提了一下rebase。 是因为r…

音视频流媒体直播/点播系统EasyDSS互联网视频云平台介绍

随着互联网技术的飞速发展,音视频流媒体直播已成为现代社会信息传递与娱乐消费的重要组成部分。在这样的背景下,EasyDSS互联网视频云平台应运而生,它以高效、稳定、便捷的特性,为音视频流媒体直播领域带来了全新的解决方案。 1、产…

HarmonyOS4+NEXT星河版入门与项目实战(22)------动画(属性动画与显示动画)

文章目录 1、属性动画图解2、案例实现-小鱼移动游戏1、代码实现2、代码解释3、资源图片4、实现效果3、显示动画4、案例修改-显示动画5、总结1、属性动画图解 这里我们用一张完整的图来汇整属性动画的用法格式和使用的主要属性范围,如下所示: 2、案例实现-小鱼移动游戏 1、代…

基于大数据python 豆果美食推荐数据可视化系统(源码+LW+部署讲解+数据库+ppt)

!!!!!!!!! 很对人不知道选题怎么选 不清楚自己适合做哪块内容 都可以免费来问我 避免后期給自己答辩找麻烦 增加难度(部分学校只有一次答辩机会 没弄好就延迟…

坐标系变换

1 Clark变换 三相对称电压表达式为: 将三相电压用相量的形式表达出来,并用欧拉公式(eix(cosxisinx))写成三角函数的形式: 同时,三相电压矢量空间合成向量可表示为: 三相电压合成矢量幅值为相电…

008静态路由-特定主机路由

按照如上配置,用192.168.0.1 电脑ping 192.168.1.1 发现能够ping通 用192.168.0.1 电脑ping 192.168.2.1 发现不能ping通 这是因为192.168.0.1 和 192.168.1.1 使用的是同一个路由器R1。 192.168.0.1 和 192.168.2.1 通信需要先经过R1,再经过R2 &#xf…

用c语言完成俄罗斯方块小游戏

用c语言完成俄罗斯方块小游戏 这估计是你在编程学习过程中的第一个小游戏开发,怎么说呢,在这里只针对刚学程序设计的学生,就是说刚接触C语言没多久,有一点功底的学生看看,简陋的代码,简陋的实现&#xff0…

数据迁移调研

需求背景:在项目迭代过程中,需要将一个数据库的数据迁移到另外一个数据库,包括分库分表的mysql数据库的数据异构到ES,来支持大数据量的查询,以及从一个Mysql数据库迁移到另外一个Mysql数据库的操作。多个业务的数据在一…