MOV moffs32在64位模式下地址的符号扩展还是零扩展? [英] Sign or Zero Extension of address in 64bit mode for MOV moffs32?
问题描述
让我们以 64位模式将指令 MOV EAX,[0xFFFFFFFF]
编码为 67A1FFFFFFFF
(有效的地址大小由67个前缀默认为64到32位).
Let's have an instruction MOV EAX,[0xFFFFFFFF]
encoded in 64bit mode as 67A1FFFFFFFF
(effective address-size is toggled by 67 prefix from default 64 to 32 bits).
Intel的说明参考手册(从2015年12月起,文档订单号:325383-057US)在第Vol. 2A 2-11说:
Intel's instruction reference manual (doc Order Number: 325383-057US from December 2015) on page Vol. 2A 2-11 says:
2.2.1.3排量
在64位模式下寻址使用现有的32位ModR/M和SIB编码. ModR/M和SIB大小不变.他们 保留8位或32位,并符号扩展为64位.
2.2.1.3 Displacement
Addressing in 64-bit mode uses existing 32-bit ModR/M and SIB encodings. The ModR/M and SIB sizes do not change. They remain 8 bits or 32 bits and are sign-extended to 64 bits.
这表明应该对32位位移进行符号扩展,但是我不确定这是否也涉及特殊的moffs寻址模式. 英特尔在下一页上说:
This suggests that 32bit displacement should be sign-extended but I am not sure if this concerns special moffs addressing mode as well. On the next page Intel says:
2.2.1.6 RIP相对寻址
2.2.1.6 RIP-Relative Addressing
RIP相对寻址是通过64位模式而不是64位地址大小启用的.使用 address-size前缀不会禁用RIP相对寻址.这 地址大小前缀的作用是截断和零扩展 计算出的有效地址为32位.
RIP-relative addressing is enabled by 64-bit mode, not by a 64-bit address-size. The use of the address-size prefix does not disable RIP-relative addressing. The effect of the address-size prefix is to truncate and zero-extend the computed effective address to 32 bits.
这表明在相对寻址模式下,disp32被符号扩展为64位,添加到RIP,然后被截断并零扩展. 但是,我不确定同一规则是否适用于绝对寻址模式,MOV moffs操作就是这种情况.
This suggests that in relative addressing mode the disp32 is sign-extended to 64 bit, added to RIP and then truncated and zero-extended. Hovever I am not sure if the same rule applies to absolute addressing mode, which is the case of MOV moffs operations.
将从AAX加载什么地址,A)FFFFFFFFFFFFFFFF或B)00000000FFFFFFFF?
推荐答案
67 A1 FFFFFFFF
没有使用disp32
寻址模式,因此该文档的Mod/RM部分不适用.
67 A1 FFFFFFFF
isn't using a disp32
addressing mode, so the Mod/RM section of the documentation doesn't apply.
英特尔x86手册第1卷说:
Intel's x86 manual vol.1 says:
在IA-32e模式下,所有16位和 32位地址计算都进行零扩展,以形成64位地址.首先,地址计算将被截断为当前模式(64位模式或兼容模式)的有效地址大小,并被任何地址大小前缀覆盖.然后将结果零扩展到整个64位地址宽度. [...]在64位模式下生成的32位地址只能访问64位模式有效地址的低4 GB.
All 16-bit and 32-bit address calculations are zero-extended in IA-32e mode to form 64-bit addresses. Address calculations are first truncated to the effective address size of the current mode (64-bit mode or compatibility mode), as overridden by any address-size prefix. The result is then zero-extended to the full 64-bit address width. [...] A 32-bit address generated in 64-bit mode can access only the low 4 GBytes of the 64-bit mode effective addresses.
这也适用于mov
的特殊 moffs
绝对寻址形式关于常规的ModR/M寻址模式,例如mov eax, [edi]
而不是mov eax, [rdi]
.
This applies to the special moffs
absolute addressing forms of mov
as well as to regular ModR/M addressing modes like mov eax, [edi]
instead of mov eax, [rdi]
.
请注意,moffs8/16/32/64
命名显示的是操作数大小,而不是地址大小(例如mov al, moffs8
).对于64位模式下的32位地址大小moffs
没有不同的术语.
Note that the moffs8/16/32/64
naming shows the operand-size, not the address size (e.g. mov al, moffs8
). There isn't a different term for a 32-bit address size moffs
in 64-bit mode.
地址大小前缀将A1
操作码从64位立即地址更改为32位,即,它更改了指令 rest 的长度(与ModR/M不同)寻址模式(始终为disp0/8/32)(64位模式).根据我的测试,实际上导致LCP在Skylake上停止运行 a32 mov eax, [abs buf]
(NASM选择在这种情况下使用moffs编码,因为指定了a32
替代,它比ModR/M + disp32短)
The address-size prefix changes the A1
opcode from a 64-bit immediate address to a 32-bit, i.e. it changes the length of the rest of the instruction (unlike ModR/M addressing mode in 64-bit mode, which are always disp0/8/32). This actually causes LCP stalls on Skylake, according to my testing, for a32 mov eax, [abs buf]
(NASM chooses to use the moffs encoding for that case, because with the a32
override specified, it's shorter than ModR/M + disp32)
无论如何,这意味着将其反汇编为mov eax, [0xFFFFFFFF]
是错误的(至少在NASM语法中如此),因为它将重新组合成一条执行不同操作的指令.
Anyway, this means that disassembling it as mov eax, [0xFFFFFFFF]
is wrong (at least in NASM syntax), because that assembles back into an instruction that does something different.
正确的YASM/ NASM语法将重新组合机器代码是
The correct YASM/NASM syntax that will assemble back to that machine code is
NASM也接受mov eax, [a32 0xFFFFFFFF]
,但YASM不接受.
NASM also accepts mov eax, [a32 0xFFFFFFFF]
, but YASM doesn't.
GNU as
还提供了一种表达它的方式(不使用.byte
):
addr32 mov 0xffffffff,%eax
GNU as
also provides a way to express it (without using .byte
):
addr32 mov 0xffffffff,%eax
movl 0x7FFFFFFF, %eax # 8B mod/rm disp32
movl 0xFFFFFFFF, %eax # A1 64bit-moffs32: Older GAS versions may have required the movabs mnemonic to force a moffs encoding
movabs 0x7FFFFF, %eax # A1 64b-moffs32: movabs forces MOFFS
movabs 0xFFFFFFFF, %rax # REX A1 64b-moffs64
movabs 0xFFFF, %ax # 66 A1 64b-moffs64: operand-size prefix
.byte 0x67, 0xa1, 0xff, 0xff, 0xff, 0xff # disassembles to addr32 mov 0xffffffff,%eax
# and that syntax works as assembler input:
addr32 mov 0xffffffff,%eax # 67 A1 FF FF FF FF: 32b-moffs32
对于NASM/YASM,无法以除拒绝AL/AX/EAX/RAX以外的其他寄存器汇编的方式强制强制执行32位MOFFS编码. a32 mov [0xfffffff], cl
组装为67 88 0c 25 ff ff ff 0f addr32 mov BYTE PTR ds:0xfffffff,cl
(mov r/m8, r8
的ModR/M + disp32编码).
With NASM/YASM, there's no way to force a 32-bit MOFFS encoding in a way that refuses assemble with a register other than AL/AX/EAX/RAX. a32 mov [0xfffffff], cl
assembles to 67 88 0c 25 ff ff ff 0f addr32 mov BYTE PTR ds:0xfffffff,cl
(a ModR/M + disp32 encoding of mov r/m8, r8
).
您可以编写mov eax, [qword 0xffff...]
以获得moffs64
编码,但是无法要求32位moffs编码.
You can write mov eax, [qword 0xffff...]
to get the moffs64
encoding, but there's no way to require a 32-bit moffs encoding.
Agner Fog的objconv
反汇编程序弄错了(从上面的块中反汇编GNU as
生成的机器代码). objconv
似乎采用符号扩展名. (它将机器代码放在注释中为prefixes: opcode, operands
)
Agner Fog's objconv
disassembler gets it wrong (disassembling the machine code produced with GNU as
from the block above). objconv
appears to assume sign-extension. (It puts the machine code in comments as prefixes: opcode, operands
)
; Note: Absolute memory address without relocation
mov eax, dword [abs qword 7FFFFFH] ; 0033 _ A1, 00000000007FFFFF
...
; Note: Absolute memory address without relocation
mov eax, dword [0FFFFFFFFFFFFFFFFH] ; 0056 _ 67: A1, FFFFFFFF
ndisasm -b64
也会错误地反汇编,导致代码甚至无法以相同的方式工作:
ndisasm -b64
also disassembles incorrectly, to code that doesn't even work the same way:
00000073 A1FFFF7F00000000 mov eax,[qword 0x7fffff]
-00
...
00000090 67A1FFFFFFFF mov eax,[0xffffffff]
如果不使用a32
关键字,我会期望像mov eax, [qword 0xffffffff]
这样的反汇编.这将汇编成一个64位的moffs,该moffs引用与原始地址相同的地址,但更长.当向ndisasm添加AMD64支持时,这可能被忽略了,而ndisasm在AMD64之前已经存在.
I would have expected a disassembly like mov eax, [qword 0xffffffff]
, if it's not going to use the a32
keyword. That would assemble to a 64-bit moffs that references the same address as the original, but is longer. Probably this was overlooked when adding AMD64 support to ndisasm, which already existed before AMD64.
这篇关于MOV moffs32在64位模式下地址的符号扩展还是零扩展?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!