0

In our application, I have the following source code:

#define GET_CALL_ADDRESS(VAR) asm("movl 4(%%ebp),%0;" : "=r"(VAR));

void * _our_malloc(size_t size)
{
    unsigned long calladdr;
    ...
    GET_CALL_ADDRESS(calladdr);
    ...
    return p;
}

I would like to know what does GET_CALL_ADDRESS do ? This code compiles and works fine on 32-bit machine.

But on 64-bit machine, during compilation I get the following error:

Error: incorrect register `%rax' used with `l' suffix
Monku
  • 2,440
  • 4
  • 33
  • 57
  • Not a good idea, there may not even be a stack frame, %ebp is a 32-bit register your error suggests you are compiling as 64-bit code. – Michael Petch Jan 26 '17 at 19:43
  • Yes we are in development of moving to 64-bit. And this code worked for 32-bit previously. I would like the same code work for both 32bit and 64bit architectures – Monku Jan 26 '17 at 19:44
  • 2
    How about use GCC's builtin function to get a return address http://stackoverflow.com/a/1693025/3857942 – Michael Petch Jan 26 '17 at 19:46
  • @MichaelPetch I am not so good with assembly. Could you please tell me what exactly this macro is doing ? – Monku Jan 26 '17 at 19:47
  • That code is trying to get the return address of the calling function from the stack. And if that is production code, I recommend someone code review the project lol – Michael Petch Jan 26 '17 at 19:48
  • @MichaelPetch It executes only in debug mode. – Monku Jan 26 '17 at 19:49
  • If you want the return address see the link I posted above to do that. But if you really want to directly translate this code on 64-bit (I don't recommend this in anyway) `asm("movq 8(%%rbp),%0;" : "=r"(VAR));` – Michael Petch Jan 26 '17 at 19:55
  • 3
    You could have rewritten the macro as `#define GET_CALL_ADDRESS(VAR) (VAR)=(unsigned long)__builtin_return_address(0);` I'd prefer to change `unsigned long` to `uintptr_t` available in `stdint.h` – Michael Petch Jan 26 '17 at 20:09

1 Answers1

1

The directive

asm("movl 4(%%ebp),%0;" : "=r"(VAR));

copies a 32-bit quantity from [EBP+4] to VAR. VAR in your case is defined as calladdr. This assumes that the return address is 32-bit, which is not true anymore in a 64-bit system, and it assumes that the return address is at [EBP+4], which is also not true anymore in a 64-bit system.

The reason why it fails is that calladdr is something like [EBP-x] (where x is some number like 4,) and there is no single Intel x86 instruction that will both fetch from [EBP+4] and store at [EBP-x], so the value fetched from [EBP+4] must be stored in some register, and then the value of that register must be stored at [EBP-x]. Then for some unknown to me reason gcc decides to use register rax for this job, but rax is 64-bit wide, while the 'l' prefix of the movl instruction implies a 32-bit quantity, so there is a mismatch.

Even if you somehow managed to sort this out, your next problem would be that on a 64-bit architecture, the return address is not at [EBP+4].

So, this entire clause is an assumption that you are in 32-bits.

My recommendation: completely ditch this nonsense and replace it with some ready-made library (no need to re-invent the wheel) that works both in 32-bit and 64-bit mode, or with gcc's built-in function for retrieving the return address, as suggested by Michael Petch; then proceed to rebuild in 64-bit like a boss.

Mike Nakis
  • 56,297
  • 11
  • 110
  • 142
  • That's not the reason why it fails; the `"r"` specifier tells gcc to out `VAR` in a register. – fuz Jan 26 '17 at 21:30
  • @fuz yes, but it does not specify the register. Then again, I understand why gcc chooses `rax`: it is because calladdr is 64-bit. – Mike Nakis Jan 26 '17 at 21:47
  • gcc chooses `rax` because `calladdr` has type `unsigned long` which is a 64 bit type in the amd64 sysv abi. Seriously, your answer is full of wrong information, perhaps you should read the manual and rewrite it. – fuz Jan 26 '17 at 22:06
  • Uhm, that's what I wrote. In any case, if you believe you have all the right information, you are free to post an answer. Let's see how different from mine it will be. – Mike Nakis Jan 26 '17 at 22:11