x86_64汇编系列:
x86_32汇编中的大部分指令在x86_64中都有对应,功能相同,只不过x86_64上的对应指令可能支持操作64位的地址、操作数和寄存器。
需要注意的是,x86_64中操作的地址不一定非得是64位,也可以是32位的。例如,x86_64支持下面的指令:
mov r10, [eax]
其中,eax
的内容就是地址,这个32位的地址前面会被补上32位的0,也就是说,eax
只能寻址内存空间的低4GB。通常是不推荐使用32位的地址的,推荐使用64位。
此外,x86_64指令所操作的寄存器和操作数并也不非得是64位,也可以操作8位、16位、32位的寄存器或数。
说到立即数,需要额外注意一下。x86_64的汇编指令中并非所有指令都支持64位的立即数:
- 绝大多数指令都最多支持32位的立即数。以
pushq
指令为例,pushq $0x1122334455667788
指令尝试push一个64位的立即数,这会导致编译错误。
那么,如果我们是在一个64位的上下文中使用32位的立即数,会怎么样呢?这个32位的立即数将会被符号扩展成64位的。- 只有
mov
指令是一个特例,它可以支持64位的立即数。参考:https://stackoverflow.com/questions/13351363/push-on-64bit-intel-osx
虽然x86_64汇编指令支持操作8/16/32位的寄存器,但是这样做可能会产生某些副作用。
以RAX/EAX
寄存器为例,假设一开始RAX的内容是0x8000000000000000
。执行add eax, 10
指令,会导致RAX
的高32位被清0,然后低32位才加上10,所以结果是0x000000000000000A
。
但是,当使用x86_64汇编指令操作8位寄存器AL
和16位寄存器AX
时,却不会导致高位清0,高位保持不变。
此外,x86_64还规定了如果一个指令使用了AH, BH, CH, DH
其中一个寄存器,那么该指令就不能再使用SIL, DIL, BPL, SPL, R8B - 15B
这些8位寄存器。