数据传送mov
汇编mov精要
mov的后缀
mov指令根据操作的数据size不同,具有不同的后缀指示
movb
(传送字节)movw
(传送字)movl
(传送双字)movq
(传送四字)
C声明 | Intel数据类型 | 汇编代码后缀 | 大小(byte) |
---|---|---|---|
char | 字节 | b | 1 |
short | 字 | w | 2 |
int | 双字 | l | 4 |
long | 四字 | q | 8 |
char* | 四字 | q | 8 |
float | 单精度 | s | 4 |
double | 双精度 | l | 8 |
注:
后缀l
代表传送双字,因为32bit被看作是长字(long-word)。但是汇编中也使用l
代表4字节整数
和8字节双精度浮点数
。大家可能会疑惑,那机器如何区分后缀为l时,表示的是上述的那种情况呢?事实上,当操作对象为浮点数的时候,使用的是一组完全不同的指令和寄存器,所以不会产生二义性。
操作数指示符
imm(rb,ri,s)
事实上上面的表示方式是最通用的,可以达到触类旁通的效果
这个表示形式会被计算为
I
m
m
+
R
[
r
b
]
+
R
[
r
i
]
∗
s
Imm+R[r_b]+R[r_i]*s
Imm+R[rb]+R[ri]∗s
可以理解为
- Imm:偏移量,是个立即数
- rb:基址寄存器
- ri:变址寄存器
- s:比例因子
movq
与movabsq
movabsq
传送绝对的四字,以任意的64bit立即数为原操作数,且只能以寄存器为目的
movq
常规情况下只能以32bit补码数字的立即数为源操作数,然后符号扩展为64bit,放到目的。
MOVZ
和MOVS
当把size较小的源值复制到较大的目的时使用,且源来自主存或寄存器,目的只能是寄存器。
且只有在movz和movs中,后面的指示数据size的后缀才能写两位
movz
把目的中剩余字节填充为0
指令 | 效果 | 描述 |
---|---|---|
MOV S ,R | R<-零扩展(S) | 以0扩展进行传送 |
movzbw | 字节0扩展传送到字 | |
movzbl | 字节0扩展传送到双字 | |
movzbq | 字节0扩展传送到四字 | |
movzwl | 字0扩展传送到双字 | |
movzwq | 字0扩展传送到四字 |
注
目的的size一定是要大于源的
指令 | 效果 | 描述 |
---|---|---|
MOV S, R | R<-符号扩展(S) | 以符号扩展进行传送 |
movsbw | 字节符号扩展传送到字 | |
movsbl | 字节符号扩展传送到双字 | |
movsbq | 字节符号扩展传送到四字 | |
movswl | 字符号扩展传送到双字 | |
movswq | 字符号扩展传送到四字 | |
movslq | 双字符号扩展传送到四字 | |
cltq | %rax<-符号扩展(%eax) | 把%eax符号扩展到%rax |
注
cltq只能作用于%eax和%rax
对比上述两个表,发现为什么没有movzlq?
绝大多数情况下,mov只会改变指定的寄存器字节或内存,但是对于movl来说,当它的目的为寄存器时,那么除了指定要改变的部分外,还会自动将该寄存器的高4字节置0,所以以寄存器为目的的movl,其作用就相当于movzlq。
注
另外注意,当涉及强制类型转化的时候,既涉及数据size的转换,又涉及数据有无符号的转换时,先转换大小,再转化符号。