汇编学习教程:寻址大总结

前言

在上篇博文中,我们主要学习了一个全新的寄存器:bp。bp 寄存器在功能和使用上与 bx 有着异曲同工之妙,只不过两人绑定的服务对象不同:bx 默认绑定的是 DS 段寄存器,而 bp 默认绑定的是 SS 段寄存器。bx 和 bp 有着相同的灵活寻址,但是两者却不能组合在一起使用,所以我们确认 bp 是  bx 的兄弟,而不是伙伴。

截至到此,目前我们基本把已有的灵活寻址给学习完了,本篇博文中将主要对已学过的灵活寻址做一个归纳总结,加深我们的学习印象,下面就让我们赶快开始本篇的学习吧!

BX和他的伙伴们

首先要隆重请出最主要的人:bx!

BX

bx 做为一个通用寄存器,已经是我们老熟人了,这里不再作过多的介绍。这里我们要明白的是,在汇编编程中,bx 和 [bx] 之间的区别。

在汇编指令中,bx只是一个存储数据的地方,例如指令:mov ax,bx,就是把bx寄存器中的值赋值到ax寄存器内,执行完毕后,ax寄存器中的值就是bx寄存器中的值;指令:mov bx,ax,则是把ax寄存器中的值赋值到bx寄存器,执行完毕后,bx寄存器中的值就是ax寄存器中的值。由此可见,汇编指令中的 bx 用法,只是充当一个数据存储角色。

但是当bx穿上马甲,变身为 [bx],事情就变得不一样了起来~例如指令:mov ax,[bx],则是将内存地址为 ds:bx 下的一个字数据送入ax寄存器内,此时bx的值就是一个偏移地址,而ds寄存器中的值就是数据段段地址,ds和bx相互配合完成了寻址操作。

总结:

1、在汇编语句中,bx的作用则是一个数据存储器,存放一个字的数据或者一个字节的数据,指令操作的是bx寄存器内的数据

2、在汇编语句中,[bx] 的作用则是代表内存中的一处内存地址,此时bx内的数据值表示偏移值。CPU会默认将DS寄存器中值当作数据段段地址,与bx寄存器中的值合成一个20位的内存地址进行寻址。指令操作的是内存地址 ds:bx 下的数据。

3、[bx] 是和 DS 寄存器强关联关系,CPU会默认段地址为DS寄存器中的值,偏移地址为 bx 寄存器中的值。例如指令你可以这样写:mov ax,[bx],或者写成:mov ax,ds:[bx],这样都是可以的。

4、必须是 [bx],[bl] 是错误的

idata

这是bx的第一个小伙伴,idata,它在汇编编程中表示一个立即数,也就是一个常量,在程序运行的过程中无法改变其值。例如指令:mov ax,idata,意思为将ax寄存器的值赋值为idata,执行完毕后,ax寄存器中的值就是idata。

做为bx的小伙伴,bx可以穿马甲,idata当然也是可以穿上马甲的,成为 [idata]!在汇编语句中,[idata] 的作用基本和 [bx] 一致,唯一区别是由于 idata是一个立即数常量,程序运行中无法修改,所以 [idata] 在程序整个运行周期中,始终表示一个偏移地址。例如指令:mov ax,[idata],意思为将段地址为ds寄存器的值、偏移地址为idata 下的一个字数据送入ax寄存器中。

不过这里有一个注意点,在此前的博文中已经提及过,有忘记的伙伴可以回头温故一下:【bx的作用】,那就是debug工具和masm工具两者对 [idata] 的理解、处理不同。

在debug工具中你可以直接使用 [idata] 的形式,但是在写源代码的时候,则不能直接使用 [idata],因为masm工具对于 [idata] 这种形式只会编译成一个立即数 idata,而不是认为这是一个偏移地址。为了让masm准确编译,我们需要加上强指定,即在源程序中使用:ds:[idata],这样告诉masm这是一个偏移地址,才能准确编译。

总结:

1、在汇编语句中,idata 表示为一个自然数、常量,程序运行期间无法动态修改。

2、在汇编语句中,[idata] 的作用和 [bx] 相似,也是表示一个内存地址,段地址默认是DS寄存器中的值,由于 idata 无法动态修改,所以在整个程序运行周期内,[idata] 始终表示同一个内存地址。

3、Debug工具使用A命令写入汇编指令,支持 [idata] 格式;使用文本编译器写源程序,用masm工具编译时,则源程序内 [idata] 格式编译后 与 idata 表示效果一致,都是表示一个自然数常量,源程序内 段寄存器:[idata] 格式编译后才能正确表示这是一个内存地址。

si、di

下面我们就要介绍bx的两个小跟班,si 和 di。si 和 di 它俩是一对孪生兄弟,也就是说 si 和 di 两者拥有相同的定位和属性,他们两个主要是为了数据复制场景设计的,si的“s”是英文单词“source”,意思“来源”,所以数据复制场景中 si 通常是源数据的偏移地址;di的“d”是英文单词“destination”,意思“目的地”,所以数据复制场景中 di 通常是目的数据的偏移地址

做为bx的伙伴,大家都是可以穿马甲的,所以 si di 都可以穿上马甲成为 [si]、[di]。在汇编语句中,[si] 和 [di] 效果一致,与 [bx]效果同样保持一致。我们可以这样理解,除去数据复制这种场景外,si、di 等同于 bx 寄存器,拥有和 bx 一样的属性和能力

不过有一点例外的是,si、di 不属于通用寄存器,所存储的数据长度固定为一个字,不能向下兼容 8位的字节数据,只能是一个16位寄存器。而bx既可以当成一个16位寄存器,也可以向下兼容8位字节,拆分成两个8位寄存器:bl、bh。

总结:

1、在汇编语句中,si、di 的作用是一个数据存储器,只能存放一个字长度的数据

2、在汇编语句中,[si]、[di] 表示一个内存地址,其中偏移地址为 si、di 中的值,段地址默认是DS寄存器中的值
3、数据复制场景下,si 表示源数据的偏移地址,di 表示目的数据的偏移地址

组合变化

介绍完bx和它的伙伴们,那么接下来我们需要讲一下他们之间友谊,也就是它们相互配合可实现的灵活寻址方式。

[bx+idata]

首先让我们通过 [bx+idata] 寻址方式来回顾 bx 和 idata 之间的友谊~

 在汇编语句中,[bx+idata] 表示为一处内存地址,该内存地址的偏移地址为 bx 寄存器中的值加上一个自然数idata,段地址默认为DS寄存器中的值。

由于idata在程序运行中无法修改,所以在该寻址方式中,idata 的值通常表示为是需要寻址的一段连续内存的起始位置,而 bx 的值则通常为这段连续内存的偏移位置。此寻址方式特性,和 c 语言中的数组是非常相似的,idata 相当于数组中下标为0的元素的地址bx 相当于数组的下标,通过修改下标值即可访问到数组中的任一元素。所以我们也可以将 [bx+idata] 寻址方式看作是一个一维数组

总结:

1、mov ax,[bx+idata],含义为:将偏移地址为 bx寄存器中的值加上一个立即数idata,段地址为DS寄存器中的值的内存地址下的一个字的数据,送入ax寄存器中

2、idata 表示为一段连续内存的起始地址,bx 则表示为这段连续内存上的偏移位置

3、[bx+idata] 寻址方式实现了类似C语言中一维数组的数据访问

[si+idata]

能和idata一起玩耍的当然不止bx一个人,si、di 都能和idata一起玩耍!

寻址方式为:[si+idata]、[di+idata]。由于 si、di 和 bx 的功能属性很相似,所以 [si+idata] 也拥有和 [bx+idata] 同样的效果,也是实现了一维数组的数据访问。这里不再过多赘述,大家参考 [bx+idata] 寻址方式即可。

[bx+si]

好朋友当然一起玩耍才更加尽兴,bx 可以和 si 或者 di 组合一起,成为一个更为灵活的寻址方式,即:[bx+si]、[bx+di]。

在汇编语句中,[bx+si] 也表示一处内存地址,该内存地址的偏移地址为 bx 寄存器中的值加上 si 寄存器中的值,段地址默认为DS寄存器中的值。因为 bx 寄存器的值和 si 寄存器、di 寄存器的值能在程序运行过程中实时修改,所以 [bx+si]、[bx+di] 的寻址形式要比 [bx+idata] 寻址形式更加灵活

由于该寻址方式中,bx、si 都可以在程序运行中实时修改,所以 [bx+si] 通常被用来实现一个二维数组的寻址。bx 用来指向每行的起始位置,si 则用来指向每行数据中的偏移位置,你也可以理解为 bx 用来定位行,si 用来定位列。

总结:

1、mov ax,[bx+si],含义为:将偏移地址为 bx 寄存器中的值加上 si 寄存器中的值,段地址为DS寄存器中的值的内存地址下的一个字数据,送入 ax 寄存器中

2、[bx+si]、[bx+di] 的寻址方式灵活程度要比 [bx+idata] 寻址方式高

3、[bx+si]、[bx+di] 寻址方式实现了类似C语言中二维数组的数据访问通常情况下,bx 用来指向二维数组中的行,si 或者 di 用来指向二维数组中的列

[bx+si+idata]

玩耍并不尽兴,一起开趴体才更加自在!bx 和它的小伙伴们一起玩耍,来一个大轰趴:[bx+si+idata]、[bx+di+idata]。

在汇编语句中,[bx+si+idata] 同样表示一处内存地址,该内存地址的偏移地址为 bx 寄存器中的值加上 si 寄存器中的值,再加上一个立即数 idata 的值,段地址默认为DS寄存器中的值。因为该寻址方式包含了 bx、si 或者 di ,在程序运行中都可以动态实时修改,所以 [bx+si+idata] 的寻址方式通常也被用来实现一个二维数组的寻址,相比 [bx+si] 寻址方式,由于立即数 idata 的加入,所以在寻址灵活程度上又提高了一点

但是立即数idata并不能在程序运行中实时修改,所以寻址灵活程度提高并不是很大。[bx+si+idata] 寻址方式中 idata 主要作用用来充当每行数据的起始地址,这样做可以保证 bx、si 初始值为0,符合汇编开发的要求规范。对此有不解的小伙伴可以回顾上篇博文【灵活寻址 四】,来加深理解。

总结:

1、mov ax,[bx+si+idata],含义为:将偏移地址为 bx 寄存器中的值加上 si 寄存器中的值,再加上一个立即数 idata 的值,段地址为 DS 寄存器中的值的内存地址下的一个字数据,送入 ax 寄存器中

2、[bx+si+idata]、[bx+di+idata] 的寻址方式灵活程度要比 [bx+idata] 寻址方式稍高

3、[bx+si+idata]、[bx+di+idata] 的寻址方式同样实现了类似C语言中二维数组的数据访问

4、idata 主要作用是定义每行数据的起始偏移位置,这样做能够保证 bx、si 或者 di 初始值为0,符合开发规范

BX 的兄弟 BP

bp 做为 bx 的兄弟,两者存在相同的灵活寻址形式。这里不再做过多讲述,简单做个总结:

总结:

1、mov ax,[bp],含义为:将偏移地址为 bp 寄存器中的值,段地址为 SS 寄存器中的值的内存地址下的一个字数据,送入 ax 寄存器中

2、mov ax,[bp+idata],含义为:将偏移地址为 bp 寄存器中的值加上一个立即数 idata,段地址为 SS 寄存器中的值的内存地址下的一个字数据,送入 ax 寄存器中

3、mov ax,[bp+si],含义为:将偏移地址为 bp 寄存器中的值加上 si 寄存器中的值,段地址为 SS 寄存器中的值的内存地址下的一个字数据,送入 ax 寄存器中

4、mov ax,[bp+si+idata],含义为:将偏移地址为 bp 寄存器中的值加上 si 寄存器中的值,再加上一个立即数 idata 的值,段地址为 SS 寄存器中的值的内存地址下的一个字数据,送入 ax 寄存器中

绑定的段寄存器

bx 默认绑定的是 DS 段寄存器,但并不是只能是 DS 段寄存器,还可以是 ES 段寄存器、CS 段寄存器、SS 段寄存器。要想让 bx 与 ES、CS、SS 搭上关系,我们需要在汇编指令中使用强指定的手段,才可以使用。强指定形式为:段寄存器:[bx],不过需要注意的是,强指定的形式仅 MASM 工具支持,Debug 工具是不支持的

示例

这里我们打开 Debug,使用 A命令插入以下指令:mov ax,cs:[bx]、mov ax,ss:[bx]、mov ax,ds:[bx]、mov es:[bx],看是否通过:

可以看到,上述四条使用强指定的汇编语句,均未通过。

那么,下面我们使用 Notepad++  编写汇编,使用 MASM 工具编译,看是否编译通过,代码如下:

assume cs:code

code segment
    start:
	    mov ax,cs:[bx]
        mov ax,ss:[bx]
        mov ax,ds:[bx]
        mov ax,es:[bx]
		
        mov ax,4c00H
		int 21H
code ends
end start

 编译结果如下:

 可以看到正常通过编译,那么接下来我们链接生成 exe 文件,使用 Debug 工具查看编译生成的汇编指令:

加载 exe 文件后,我们使用 U 指令查看 076a:0~10 空间内的汇编指令,如上图所示。

 从图中我们可以看到编译的区别:虽然都是使用的强指定形式,但是 mov ax,ds:[bx] 指令编译后,指令前并未出现 DS: 。而其他的指令,例如 mov ax,cs:[bx],指令前出现了 CS:,表示下面的 [bx] 偏移位置为 CS 代码段中。

之所以会出现这样的不同是因为,[bx] 默认绑定的段寄存器就是 DS,也就是说指令:mov ax,ds:[bx] 是等同于指令:mov ax,[bx]。那么 MASM 工具编译的时候,碰到 ds:[bx],就自动省略掉 ds:,将其当作 [bx] 来编译看待,所以我们查看编译后的指令,自然 MOV 指令前没有了 DS:。

错误的寻址

接下来我们说一下错误的寻址方式。

si、di

si 寄存器、di 寄存器他们两个虽然是一对亲兄弟,但是他们两个却是无法在一起使用,一旦相见就像是仇人相见分外眼红一般,无法共存。这里我们直接打开 debug 程序,使用A命令写入下面这条汇编语句:mov ax,[si+di],看下是否通过:

 从上图中可以看到,debug 直接提示了错误,也就是说 si、di 在寻址中是无法共同存在的。

那么也就意味着,以下几条汇编语句都是错误的:

1、mov ax,[si+di]

2、mov ax,[bx+si+di]

3、mov ax,[idata+si+di]

4、mov ax,[bp+si+di]

以上汇编语句所犯错误之处都是出现了 si、di 共存,这在汇编中是不允许的。

bx、bp 

 正所谓一山不容二虎,bx 寄存器和 bp 寄存器同样无法一起共存。在 debug 程序中使用 A 命令写入下面这条汇编语句:mov ax,[bx+bp],观察是否通过:

我们可以看到 debug给出了错误提示,提示我们该语句不符合规则。

那么也就意味着,以下几条汇编语句都是错误的:

1、mov ax,[bx+bp]

2、mov ax,[bx+bp+idata]

3、mov ax,[bx+bp+si]

4、mov ax,[bx+bp+di]

以上汇编语句所犯错误之处都是出现了 bx、bp 共存,这在汇编中是不允许的。

总结

这里贴出一张寻址全家福:

这张图里详细展示了目前我们已经学习过了所有灵活寻址方式,大家在后面的汇编开发中可以参考学习。

本篇结束语

本篇主要是对过往我们学习过的灵活寻址方式进行一个归纳总结,从而加深我们的印象。在后面的编程实例中,我们将会对众多灵活寻址进行实战演练,并逐步掌握不同的开发场景应对不同的寻址方式。

感谢围观,转发分享请标明出处,谢谢~

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Unity之透明度混合与ps的透明度混合计算结果不一致

一、问题 前段时间学习shader时发现了一个问题,一张纯红色透明度为128的图片叠加在一张纯绿色的图片上得出的结果与ps中的结果不一致。网上查找了ps中的透明混合的公式为 color A.rgb*A.alpha B.rgb*(1-A.alpha)。自己使用代码在unity中计算了一下结果总是不对。…

【Java基础学习打卡09】JRE与JDK

目录 前言一、JRE二、JDK三、JDK、JRE和JVM关系总结 前言 本文将介绍JRE、JDK是什么,以及JDK、JRE和JVM关系三者之间的关系。 一、JRE JRE全称为Java Runtime Environment,是Java应用程序的运行时环境。JRE包括Java虚拟机(JVM)、…

车辆救援道路救援预约汽修托运小程序

道路救援:指汽车道路紧急救援,为故障车主提供包括诸如:拖吊、换水、充电、换胎、送油以及现场小修等服务(Road-Side Service); 同时也指交通事故道路救援,包括伤员救治、道路疏导等。 随着我国巨大的汽车拥有量&…

基础篇:新手使用vs code新建go项目(从0开始到运行)

学习新语言,搭建新环境。在网上找了一些教程,感觉还是写一个比较详细的方便以后自己使用。其实vs code没有新建项目这个功能,具体怎么运行go语言的项目请看下文。 一、下载GO安装包 1.点击go安装包下载链接下载相应的版本(本次下…

了解 Dockerfile 和搭建 Docker 私有仓库:让容器化部署变得更简单

目录 1、Dockerfile 1.1什么是Dockerfile 1.2常用命令 1.3使用脚本创建镜像 2、Docker私有仓库 2.1私有仓库介绍: 2.2私有仓库搭建与配置 2.3上传镜像到私有仓库: 1、Dockerfile 1.1什么是Dockerfile Dockerfile是由一些列命令和参数构成的脚本…

《网络安全0-100》安全事件案例

网络安全事件案例分析 2017年Equifax数据泄露事件 Equifax是美国一家信用评级机构,2017年9月,该公司披露发生了一起重大的数据泄露事件,涉及1.43亿美国人的个人信息,包括姓名、出生日期、社会安全号码等敏感信息。经过调查&#…

【数据分析】如何使用docker部署程序并移植(算法、接口)

原文作者:我辈李想 版权声明:文章原创,转载时请务必加上原文超链接、作者信息和本声明。 文章目录 前言一、Docker的基本使用1.安装Docker2.列出本地镜像3.获取镜像,创建本地ubuntu:13.10镜像4.查找镜像5.删除本地镜像6.创建自定义镜像7.镜像…

第一章 基础算法(二)——高精度,前缀和与差分

文章目录 高精度运算高精度加法高精度减法高精度乘法高精度除法 前缀和二维前缀和 差分二维差分 高精度练习题791. 高精度加法792. 高精度减法793. 高精度乘法794. 高精度除法 前缀和练习题795. 前缀和796. 子矩阵的和 差分练习题797. 差分798. 差分矩阵 高精度运算 两个大数做…

【Unity Shader】从入门到感慨(2)用C#画一个立方体

文章目录 一、构成一个立方需要多少个顶点?二、定义三角面的索引数组:三、定义UV坐标数组:四、最后构建Mesh:五、完整代码:一、构成一个立方需要多少个顶点? 这个问题是面试经常被问到的题。如上图,我们知道在几何中立方体有6个面,8个顶点。但在图形学中,顶点指的是模…

翻过那座山——Gitlab流水线任务疑难之编译有子模块的项目指南

📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!📢本文作者:由webmote 原创📢作者格言:新的征程,我们面对的不是…

QT入门基础知识

什么是QT QT是一个跨平台的C图像用户界面应用程序框架QT在1991年由奇趣科技开发QT的优点 跨平台,几乎支持所有平台接口简单,容易上手一定程度上简化了内存回收机制有很好的社区氛围可以进行嵌入式开发 QWidget QT注意事项 命名规范 类名 首字母大写,单…

golang vscode环境报错gopls was not able to find modules in your workspace的解决方式

目录 错误提示 分析 解决方式 方法一:将workspace与项目路径保持一致 方案二:使用go work指明纳入工作区的的module 总结 错误提示 golang从老版本升级到go1.20.5后打开vscode,发现代码不能自动补全了,而且vscode跳出一下的…

微服务基础介绍

Part1一、基本概念 微服务最主要的功能是根据业务拆分成一个一个的子服务,实现功能的去耦合,每一个微服务提供单个业务功能的服务,各司其职,从技术角度看就是一种灵活独立的单元,能够自行单独启动和关闭,一…

Docker学习笔记1

PaaS: 一、虚拟化分类: 虚拟化资源提供者: 1)硬件平台虚拟化 2)操作系统虚拟化 虚拟化实现方式: type I: 半虚拟化 type II:硬件辅助全虚拟化 type III: 软件全虚拟化: …

【C++】模版进阶

目录 一、非类型模版参数二、模板的特化1、概念2、函数模版特化3、类模板特化1.全特化2.偏特化3.类模板特化应用示例 三、模版分离编译1、什么是分离编译2、模板的分离编译3、模板的优缺点 一、非类型模版参数 模版参数分为类型模版参数与非类型模版参数 类型模版参数&#x…

[进阶]网络通信:UDP通信,一发一收、多发多收

UDP通信 特点:无连接、不可靠通信。不事先建立连接;发送端每次把要发送的数据(限制在64KB内)、接收端1P、等信息封装成一个数据包,发出去就不管了。Java提供了一个java.net.Datagramsocket类来实现UDP通信。 Datagram…

Springboot项目使用原生Websocket

目录 1.启用Websocket功能2.封装操作websocket session的工具3.保存websocket session的接口4.保存websocket session的类5.定义websocket 端点6.创建定时任务 ping websocket 客户端 1.启用Websocket功能 package com.xxx.robot.config;import org.springframework.context.a…

NSSCTF MOBILE [SWPU 2019]easyapp 详细题解

文章目录 一. 前言二. 安装安卓SDK三. 安装安卓模拟器(推荐夜神模拟器)四. 安装frida和objection五. 解题过程六. 总结 一. 前言 题目地址:[SWPU 2019]easyapp大佬题解[SWPU 2019]easyapp pwjcw的WriteUp 大佬的题解很简单,直接hook就可以看到返回值,但是我看了半天没看明白是…

Redis简介

Redis是基于内存,也可以基于磁盘持久化nosql数据库,使用c语言开发。 数据存储结构:key-value 安装环境准备 Redis使用c语言开发,需要使用gcc编译程序进行编译。 1) 安装gcc a) 从磁盘镜像中进行安装:&…

决策树分类算法

#CSDN AI写作助手创作测评 目录 ID3算法 1.算法原理 2.代码实现 3.ID3算法的优缺点分析 C4.5算法 1.原理 2.优缺点 心得感受 决策树表示方法是应用最广泛的逻辑方法之一,它从一组无次序、无规则的事例中推理出决策树表示形式的分类规则。在决策树的内部…