11

On x64, loading from a 64-bit absolute address (that is, dereferencing a 64-bit immediate) can be done by

movabs addr64, %rax

However, when the destination register is any other than rax the assembler gives an error message saying operand size mismatch for movabs. What am I missing?

nrz
  • 10,435
  • 4
  • 39
  • 71
Torgny
  • 279
  • 3
  • 10
  • Nit: your assembler instruction above is neither Intel nor AT&T syntax; in Intel syntax, it's `MOV RAX, [addr64]` while in AT&T it's `movabs addr64, %rax`. – FrankH. Oct 17 '13 at 09:48
  • 1
    Related on RE: http://reverseengineering.stackexchange.com/questions/2627/what-is-the-meaning-of-movabs-in-gas-x86-att-syntax – Ciro Santilli OurBigBook.com May 24 '15 at 21:06

2 Answers2

9

From the MOV instruction document you can see that you can move a 64-bit immediate to any registers, but loads/stores involving a 64-bit immediate absolute address can only work with Areg

Opcode Instruction Description
A0 MOV AL,moffs8* Move byte at (seg:offset) to AL.
REX.W + A0 MOV AL,moffs8* Move byte at (offset) to AL.
A1 MOV AX,moffs16* Move word at (seg:offset) to AX.
A1 MOV EAX,moffs32* Move doubleword at (seg:offset) to EAX.
REX.W + A1 MOV RAX,moffs64* Move quadword at (offset) to RAX.
A2 MOV moffs8,AL Move AL to (seg:offset).
REX.W + A2 MOV moffs8***,AL Move AL to (offset).
A3 MOV moffs16*,AX Move AX to (seg:offset).
A3 MOV moffs32*,EAX Move EAX to (seg:offset).
REX.W + A3 MOV moffs64*,RAX Move RAX to (offset).

As you can see there's no ModR/M byte to encode the register number. Since this is less commonly used than moving a 64-bit immediate to a register it won't be a problem. If really needed it can be done in 2 instructions

MOVABS is the GAS opcode name for the MOV opcode forms MOV Areg, [Offs64] and MOV [Offs64], Areg. In Yasm's NASM syntax mode, you can get this form by saying MOV AX, [qword xxx]. Yasm's GAS syntax mode accepts MOVABS (for GAS compatibility). Note this form is only valid with Areg (AL/AX/EAX/RAX) as the source/destination register.

http://cvs.tortall.net/pipermail/yasm-devel/2006-March/000579.html

phuclv
  • 37,963
  • 15
  • 156
  • 475
  • I don't reproduce this on Ubuntu 14.04 Intel Core i5-3210M binutils 2.25 with [this code](https://github.com/cirosantilli/assembly-cheat/blob/73dd35d9e4978ab0c461464df58ba0699fce9979/x86-64/gas/movabs.s). And the Intel manual says `MOV r64, imm64` should work. Maybe something changed since? – Ciro Santilli OurBigBook.com May 25 '15 at 08:57
  • 2
    @CiroSantilli六四事件法轮功 I think `mov r64, imm64` is valid for all registers but `mov Areg, addr64` is only valid for A registers. "`movabs %al,0xe400000000004049` is supposed to store the value of al in the address 0xe400000000004049" so it's not moving the immediate value to/from the register http://www.cplusplusdevelop.com/508_9928837/ – phuclv May 25 '15 at 16:15
  • 2
    `movabs $0x1000000000000000, %rax` is similar to `mov rax, 0x1000000000000000` but `movabs 0x1000000000000000, %rax` is similar to `mov rax, [qword 0x1000000000000000]` – phuclv May 25 '15 at 16:20
  • 2
    Ah, OK, _dereferencing_ an immediate. – Ciro Santilli OurBigBook.com May 25 '15 at 19:00
3

For any register other than %rax one can replace it by two instructions:

48 bb f0 de bc 9a 78 56 34 12   mov    $0x123456789abcdef0,%rbx
48 8b 1b                        mov    (%rbx),%rbx

This is longer than the single one,

48 a1 f0 de bc 9a 78 56 34 12   mov    0x123456789abcdef0,%rax

hence you'd quite probably prefer movabs (the latter) if you can use it.

FrankH.
  • 17,675
  • 3
  • 44
  • 63
  • Note that both forms with an 8-byte thing and no ModRM (imm64 and 64-bit absolute moffs) are called `movabs` in AT&T syntax. (And GAS / objdump uses it in Intel-syntax mode as well). Including `movabs 0x123456789abcdef0, %al`, which is a separate opcode (`a0`) from the `a1` opcode that gives us moffs16/32/64 (AX/EAX/RAX) depending on operand-size. – Peter Cordes Dec 16 '20 at 02:57
  • So, fun fact, `movabs 0x123456789abcdef0, %si` or `%dil` don't have an exact drop-in "replacement" / implementation. You need a full 64-bit register to hold the address (if RIP-relative or 32-bit absolute won't reach), but `mov` to an 8 or 16-bit register only modifies that 8 or 16 bits of register state, merging into the full reg. It's possible to imagine cases where that was actually desirable, and you didn't want to `mov $imm64, %reg` / `movzbl` or `movsbl` extending load into the full register. – Peter Cordes Dec 16 '20 at 03:06
  • @PeterCordes: I'd recommend xchg/mov64/xchg. (Where the first xchg could be a mov but xchg with rax has a short encoding). – Joshua Dec 16 '20 at 03:24
  • @Joshua: Interesting, yes that would do the trick without needing to spill any architectural state from registers to anywhere else. When AL/AX is special, look to 8086 techniques. :P (But no, mov doesn't make sense. If the old contents of RAX weren't precious, you would `mov $imm64, %rax` and use `(%rax)`. Or `movabs mem, %al` / `mov %al, %dil`, which even works if only the low 8 or 16 bits of RAX can be clobbered. If it was a word load, then yes you could save a byte with 66 90+reg `xchg %ax, reg` instead of 3-byte `mov %ax,reg`, at the cost of more uops.) – Peter Cordes Dec 16 '20 at 03:36