assemblyx86x86-64objdumpinstruction-encoding

Encoding "MOV EAX, moffs32" on x86-64


I have stumbled across the "MOV EAX, moffs32" instruction while trying to understand x86-64.

Table

As far as I can tell, this instruction would get encoded (with an moffs32 of 0x12345678) to just A1 78 56 34 12.

When I run this through a disassembler, however, I get garbage:

# objdump -D -b binary -mi386 -Mx86-64 -Mintel file.bin
00000000 <.data>:
   0:   a1                      .byte 0xa1
   1:   78 56                   js     0x59
   3:   34 12                   xor    al,0x12

Same goes for ndisasm:

# ndisasm -b 64 file.bin
00000000  A1                db 0xa1
00000001  7856              js 0x59
00000003  3412              xor al,0x12

I only get the instruction back if I disassemble it for x86, not x86-64 (ndisasm -b 32):
00000000 A178563412 mov eax,[0x12345678]

Why is that? The table states that the instruction is valid for 64bit after all.
I feel like I might be missing something fundamental here, but I can't figure out what.


Solution

  • The 32 in moffs32 is only describing the operand-size, not the address-size. The address-size is still 64-bit by default in 64-bit mode.

    So it is valid in 64-bit mode, but you need more bytes for the offset, for example:

    A1 78 56 34 12 00 00 00 00
    

    That still encodes mov eax, [0x12345678], but now in 64-bit mode. This instruction is a rare case of encoding a 64-bit constant address. You can use it with a 32-bit address with an address size override:

    67 A1 78 56 34 12
    

    But note that this can be slower due to LCP stalls on Intel CPUs than the 7-byte encoding using the normal 8b 04 25 78 56 34 12 opcode for mov reg, r/m with the address as a sign-extended disp32.