6

I'm trying to make some things with GCC Inline Assembly, in this case, make a Syscall, but I want to force use of 64bit registers (rax, rdi, rsi, ...) instead of 32bit ones (eax, edi, ...), but I tried a lot of ways, and nothing.

void syscall(uint64_t arg1, uint64_t arg2) {
   // arg1 -> rax        arg2 -> rdi
   __asm__("syscall" : : "a" (arg1), "D" (arg2));
}

When I compile that I get:

mov eax, 60
syscall

I'm in a function, so "edi" is being get from arguments, but like you can see is "eax", I want to use rax.

How can I force 64bit registers instead of 32bit ones?

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • 2
    The result of most 32-bit instructions are zero-extended to the full 64-bit width. This is definitely true with the mov instruction, so "mov eax, 60" and "mov rax, 60" should have identical effect on the processor. – David Jul 18 '17 at 18:45
  • Beyond the other comments and answer. I'm assuming that you are compiling with an optimization level above `-O0`. You'd likely find that at optimization level `-O0` that _RAX_ is likely used. When optimizations are on the compiler is likely using the fact that when the destination of an operation is a 32-bit register the upper 32-bits become 0. I bet if you did an experiment where you called `syscall(0x6060606060606060, 0x7fffffffffffffff);` that the full registers _RAX_ and _RDX_ would be used since the values exceed what can be represented in 32-bits. – Michael Petch Jul 18 '17 at 21:51

1 Answers1

10

This actually sets the RAX register to 60:

mov eax, 60

Writing to EAX always clears the upper 32-bit half of the 64-bit register. This is not like AH and AL, where writes preserve the rest of the register.

If you absolutely want a move to RAX, you need to use something like this:

static inline __attribute__ ((always_inline)) void
syscall(uint64_t arg1, uint64_t arg2)
{
   __asm__("mov rax, %0; syscall" : : "i" (arg1), "D" (arg2) : "rax");
}

Note that gas will still assemble this as a 32-bit immediate move.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Florian Weimer
  • 32,022
  • 3
  • 48
  • 92
  • I know, but I want to force gcc to put `mov rax, 60` – Eduardo José Gómez Hernández Jul 18 '17 at 18:47
  • 3
    Why? This is exactly equivalent. – Jester Jul 18 '17 at 18:56
  • 1
    @OdnetninI I don't think gcc emits this instruction at all. – fuz Jul 18 '17 at 19:12
  • 2
    Just a comment to anyone reading this, the inline assembly code is using intel syntax (not default) so if one wants to use this sample they'd probably want to consider passing `-masm=intel` to _GCC_. – Michael Petch Jul 18 '17 at 22:02
  • @OdnetninI: Some assemblers (e.g. NASM) will even optimize `mov rax, 60` to `mov eax, 60` for you, because they have literally identical effects on the architectural state (except on RIP because taking 2 more bytes). YASM won't, and neither will GNU `as`, though. – Peter Cordes Jul 20 '17 at 03:05
  • some assemblers allow you to force the use of mov imm64 even when the immediate is small, for example `mov rax, strict 0` in nasm. See [What methods can be used to efficiently extend instruction length on modern x86?](https://stackoverflow.com/a/49799878/995714) – phuclv Mar 29 '22 at 13:38