前言
在上篇博文中,我们主要学习了一个全新的寄存器: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 共存,这在汇编中是不允许的。
总结
这里贴出一张寻址全家福:
这张图里详细展示了目前我们已经学习过了所有灵活寻址方式,大家在后面的汇编开发中可以参考学习。
本篇结束语
本篇主要是对过往我们学习过的灵活寻址方式进行一个归纳总结,从而加深我们的印象。在后面的编程实例中,我们将会对众多灵活寻址进行实战演练,并逐步掌握不同的开发场景应对不同的寻址方式。
感谢围观,转发分享请标明出处,谢谢~