let's have instruction mov eax,[0xffffffff]
encoded in 64bit mode 67a1ffffffff
(effective address-size toggled 67 prefix default 64 32 bits).
intel's instruction reference manual (doc order number: 325383-057us december 2015) on page vol. 2a 2-11 says:
2.2.1.3 displacement
addressing in 64-bit mode uses existing 32-bit modr/m , sib encodings. modr/m , sib sizes not change. remain 8 bits or 32 bits , sign-extended 64 bits.
this suggests 32bit displacement should sign-extended not sure if concerns special moffs addressing mode well. on next page intel says:
2.2.1.6 rip-relative addressing
rip-relative addressing enabled 64-bit mode, not 64-bit address-size. use of address-size prefix not disable rip-relative addressing. effect of address-size prefix truncate , zero-extend computed effective address 32 bits.
this suggests in relative addressing mode disp32 sign-extended 64 bit, added rip , truncated , zero-extended. hovever not sure if same rule applies absolute addressing mode, case of mov moffs operations.
what address eax loaded from, a) ffffffffffffffff or b) 00000000ffffffff ?
67 a1 ffffffff
isn't using disp32
, mod/rm section of documentation doesn't apply. moffs32
own thing. (thanks @jester clarifying it's 0 extended.)
i didn't go digging in docs clarification on moffs32
in 64bit mode. however, it's normal zero-extension when use address-size prefix (like mov eax, [esp]
instead of mov eax, [rsp]
).
anyway, means disassembling mov eax, [0xffffffff]
wrong (at least in nasm syntax), because assembles instruction different.
the correct nasm syntax assemble machine code is
mov eax, [a32 0xffffffff]
yasm doesn't support a32
keyword address-size overrides, nasm does.
gnu as
provides way express (without using .byte
): addr32 mov 0xffffffff,%eax
movl 0x7fffffff, %eax # 8b mod/rm disp32 movl 0xffffffff, %eax # a1 moffs64: movabs, no rex, because address can't encoded in disp32 movabs 0x7fffff, %eax # a1 moffs64: movabs, no rex or address-size prefix movabs 0xffffffff, %rax # rex a1 moffs64 movabs 0xffff, %ax # 66 a1 moffs64: operand-size prefix .byte 0x67, 0xa1, 0xff, 0xff, 0xff, 0xff # disassembles addr32 mov 0xffffffff,%eax # , syntax works assembler input: addr32 mov 0xffffffff,%eax # 67 a1 ff ff ff ff: moffs32
as mentioned earlier, a32
keyword works nasm, not yasm, , assemble 67 a1 moffs32
. same syntax different register assemble mov disp32 , address-size prefix. (e.g. mov ecx, [a32 0x7fffff]
assembles 67 8b 0c 25 ff ff 7f 00 addr32 mov 0x7fffff,%ecx
)
you can write mov eax, [qword 0xffff...]
moffs64
encoding, there's no way require moffs32 encoding. (i.e. in way refuse assemble if used different register.)
agner fog's objconv
disassembler gets wrong (disassembling machine code produced gnu as
block above). objconv
appears assume sign-extension. (it puts machine code in comments 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
disassembles incorrectly, code doesn't work same way:
00000073 a1ffff7f00000000 mov eax,[qword 0x7fffff] -00 ... 00000090 67a1ffffffff mov eax,[0xffffffff]
i have expected disassembly mov eax, [qword 0xffffffff]
, if it's not going use a32
keyword. assemble moffs64 references same address original, longer. overlooked when adding amd64 support ndisasm, existed before amd64.