这是关于 x86-64 (AMD64) 架构中操作数大小覆盖前缀的问题。
这是一堆汇编指令(nasm)及其编码;新的意思是 r8, ..., r15 寄存器:
67: address-size override prefix
|
| 4x: operand-size override prefix
| |
; Assembler ; | Dst operand | Src operand | -- --
mov eax,ecx ; | 32-bit | 32-bit | 89 C8 |
mov r8d,ecx ; | 32-bit new | 32-bit | 41 89 C8 |
mov eax,r9d ; | 32-bit | 32-bit new | 44 89 C8 |
mov r8d,r9d ; | 32-bit new | 32-bit new | 45 89 C8 |
mov rax,rcx ; | 64-bit | 64-bit | 48 89 C8 |
mov r8,rcx ; | 64-bit new | 64-bit | 49 89 C8 |
mov rax,r9 ; | 64-bit | 64-bit new | 4C 89 C8 |
mov r8,r9 ; | 64-bit new | 64-bit new | 4D 89 C8 |
lea eax,[ecx] ; | 32-bit | 32-bit | 67 8D 01 |
lea r8d,[ecx] ; | 32-bit new | 32-bit | 67 44 8D 01 |
lea eax,[r9d] ; | 32-bit | 32-bit new | 67 41 8D 01 |
lea r8d,[r9d] ; | 32-bit new | 32-bit new | 67 45 8D 01 |
lea rax,[rcx] ; | 64-bit | 64-bit | 48 8D 01 |
lea r8,[rcx] ; | 64-bit new | 64-bit | 4C 8D 01 |
lea rax,[r9] ; | 64-bit | 64-bit new | 49 8D 01 |
lea r8,[r9] ; | 64-bit new | 64-bit new | 4D 8D 01 |
push rax ; | | 64-bit | 50 |
push r8 ; | | 64-bit new | 41 50 |
通过研究这些以及与其他寄存器相同的指令,我推断出以下内容。“旧”和“新”寄存器之间存在配对。非详尽无遗:
AX <--> R8
CX <--> R9
DX <--> R10
BX <--> R11
BP <--> R13
忽略大小前缀,指令字节不是指特定的寄存器,而是指寄存器对。例如:字节 89 C8 表示一条 mov 指令从源(ecx、rcx、r9d 或 r9)到目标(eax、rax、r8d 或 r8)。鉴于操作数必须同时为 32 位或 64 位宽,因此有八种合法的可能组合。操作数大小覆盖前缀(或不存在)指示这些组合中的哪一个是预期的组合。例如,如果前缀存在且为 44,则源操作数必须是 32 位新寄存器(在此示例中,然后折叠为 r9d),目标必须是 32 位旧寄存器(此处为 eax 信号)。
我可能没有完全正确,但我想我明白了它的要点。这样看来,操作数大小覆盖前缀所做的覆盖是没有它们,指令将使用 32 位“旧”操作数。
但可以肯定的是,有一些事情让我无法理解,否则:谈论“默认操作数大小为 64 位的 x86-64 版本”(如这里)有什么意义?
或者有没有办法在 64 位机器上运行,将默认操作数大小设置为 32 或 64,如果是这样,并且如果我的程序适当地设置了机器,我会看到不同的编码?
另外:什么时候会使用 66H 操作数大小的覆盖前缀?