问题描述
我开始使用英特尔参考页来查找和了解操作码(而不是询问SO的所有内容)。我想确保我的理解没问题,并询问基本的asm程序和intel指令代码之间的输出问题。
这是我必须将各种mov
指令比较到rax
-ish寄存器中的程序(是否有更好的方式来说“ rax”及其32-16位和8位组件?):
.globl _start
_start:
movq $1,%rax # move immediate into 8-byte rax (rax)
movl $1,%eax # move immediate into 4-byte rax (eax)
movw $1,%ax # move immediate into 2-byte rax (ax)
movb $1,%al # move immediate into 1-byte rax (al)
mov $60,%eax
syscall
其拆卸如下:
$ objdump -D file
file: file format elf64-x86-64
disassembly of section .text:
0000000000400078 <_start>:
400078: 48 c7 c0 01 00 00 00 mov $0x1,%rax
40007f: b8 01 00 00 00 mov $0x1,%eax
400084: 66 b8 01 00 mov $0x1,%ax
400088: b0 01 mov $0x1,%al
40008a: b8 3c 00 00 00 mov $0x3c,%eax
40008f: 0f 05 syscall
我能够调和以下四个说明:
-
mov $0x1,%al
->b0 01
是,英特尔州代码为b0
[+ 1个字节的值],用于立即移动1个字节。 -
mov $0x1,%eax
->b8 01 00 00 00
是,英特尔州代码为b8
[+ 4个字节的值],用于立即移动1个字节。 -
mov $0x1,%ax
->66 b8 01 00
否,英特尔州代码为b8
而非66 b8
。 -
mov $0x1,%rax48
->c7 c0 01 00 00 00
不适用,仅32位指令。未列出。
与此相关的我的问题是:
-
mov $0x1,%ax
为什么不匹配? -
64
位代码是否有相同的表,或者建议使用哪种查找方式? - 最后,当寄存器更改时,代码如何调整?例如,如果我想将值移到
%ebx
或%r11
上。您如何计算“代码调整量”,就像在此查找表中一样,它只提供(我认为?)“eax
”寄存器作为“注册示例代码”。
解决方法
您缺少更改以下指令含义的前缀“操作码”(的概念)。 IA32 manual的第2卷第2.1.1和2.2.1节对此进行了介绍。从2.1.1得到:
Operand-size覆盖前缀使用66H编码(66H还用作某些应用程序的强制前缀 说明)。
因此66前缀会将操作数大小从默认的32位更改为16位。因此,mov $1,%ax
(16位)与mov $1,%eax
(32位)相同,只是前缀为66
最后一种情况(mov $1,%rax
)实际上使用了另一条指令
REX.W + C7 /0 io MOV r/m64,imm32 Move imm32 sign extended to 64-bits tor/m64.
在这里,我们将常量移到任何寄存器中,而不是A-指令大了一个字节,但允许将32位的imim移到64位寄存器中,因此只需要4字节的常量而不是一个8字节(因此比等效的48 b8 01 00 00 00 00 00 00 00要小3个字节)。