Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does GCC put a no-op push/pop when using int foo asm("ebx") to pin a var to a register?

Tags:

c

x86

gcc

assembly

I'm trying to write code to read from a register, and this is what I have so far:

unsigned int readEBX(void) {
    register unsigned int reg asm("ebx");
    return reg;
}

The function appears to be working, but it compiles to something strange:

readEBX():
    mov  eax, ebx
    push ebx
    pop  ebx
    ret

Why should this push-then-pop ebx? Doesn't this do nothing? When I replace ebx for another register (say eax or ecx), then it produces saner code (just a ret and a mov eax, ecx; ret respectively).

See this example Godbolt result.

like image 671
Alex Reinking Avatar asked Dec 25 '22 13:12

Alex Reinking


1 Answers

Since you are explicitly telling the compiler that you are interested in the register, he tries to be smart. Since you want to observe the register, don't tell the compiler, so he can't mess around.

This works for me (modulo the order of the mov operation)

unsigned int readEBX(void) {
  register unsigned int ret __asm__("eax");
  __asm__ volatile("mov %%ebx, %0" : "=r"(ret));
  return ret;
}

It just ensures that ret uses a different register, so there is no conflict.

like image 190
Jens Gustedt Avatar answered Dec 31 '22 13:12

Jens Gustedt