0 前言
本文基于8086汇编语言,不过x86系列语言具备向下兼容特点,大多数情况都可以用。
与高级语言数据类型的自动转换和强制转换一样,汇编语言的数据类型也有 自动匹配和手动匹配。
下面,我来介绍一下汇编语言的相关原则。
1 数据类型匹配的原则
任何时候,数据的匹配,只能是完全一样的数据类型才能进行数据传送。
也就是8位对8位,16位对16位,32位对32位。
比如
mov ax,bx
mov al,bl
请注意,这里的原则与操作数个数无关,指令如果涉及到数据传送过程,至少也要有数据提供方,有数据接收方。
需要注意,这里的数据传送,是copy,而不是remove,传送之后原来的数据不消失,只是复制过去。
你想问为什么是copy?先明白一个问题,计算机的本质,是电子计算机,是基于电的。你可以想象一下,有两根导线,中间有一个没有闭合的开关,开关闭合前,左边的是导线通电的,右边的不带电,现在将开关闭合,右边的导线是不是也通电了,左边的导线没有因此不带电吧?开关闭合后通电的过程,就是数据传送的过程,我想你大概能理解为什么是copy了。
2 自动匹配
由上面的图你可以看到,有三个部分
- 数据提供方A
- 数据传送带B
- 数据接收方C
自动匹配分为以下情况
- B大小固定:则A,C的大小自动固定
- 例如:指令push,pop要求必须是字传送,也就是B的大小限定为16
- ……
- B大小不固定:则A,C只要有一方是固定,另一方自动固定
- 例如:
mov ax,1
,因为ax
固定16位,则1
也要是16位,如果不是,需要变成16位的(插一句,这就是符号扩展) mov ax,bx
,双方都固定16位也是可以的
- 例如:
对于B固定的情况,只有很少一部分,记住即可,这里谈一下不固定的部分。
A,C分别代表数据的提供方和接收方,它们不一定是两个操作数,也可能是隐藏的,例如有的指令是单操作数,有的没有操作数,但这都不妨碍它们都有A和C。
A或C可能是
- 寄存器
- 内存单元
当一方为寄存器,例如使用ax
,则另一方就需要是16位的数据,可以是
- 寄存器,例如
bx
- 定义为
dw
类型的数据 - 某个数据的首地址,自动按16位提取,不需要加限制条件,例如
ds:[0]
- 立即数,自动扩展为16位的
当一方为dw
类型数据,也是同理。
不可以的情况:当一方为内存单元地址,另外一方为立即数,例如mov ds:[0],1
,这就是手动匹配,看下一节。
3 手动匹配
当A和C的大小都不能确定的时候,就需要手动匹配,加上限定条件了,这通常发生在<内存单元地址>
和立即数
身上,因为它们是不固定大小的,如果它们结合,或者单独出现,就必须加上限制条件。
例如
mov word ptr ds:[0],1
jmp word ptr ds:[0]
只能对内存单元地址做出规定,也就是word ptr
、byte ptr
、dword ptr
等,立即数是墙头草,别人多大他多大。
4 注意事项
需要注意的是,对于数据类型匹配这件事情,取决于编译器和CPU的设计者,大多数情况是遵循我上面所说的原则的,对于极少数特殊情况,也是完全可能的,不要因此感到惊讶。
5 小结
前面解释了很多,不过你根本没有必要记忆,只需要警惕一些特殊情况即可。
对于没有限定B部分的指令
- 双操作数指令,出现内存单元地址和立即数,地址要限定
word ptr
等类型 - 单操作数,内存单元地址要限定类型
就像赛跑,规定了起点位置和长度,就能够得到终点位置
- 起点位置就是内存单元地址,比如
ds:[0]
代表起点位置为ds*16 + 0
- 长度就是数据类型,比如
word ptr
代表长度2个字节
对于其他指令集架构,原理上是有相通性的,请读者自行思考。