I'm trying to put the value of %rbp
into the %rax
register using __asm__
so that I can get a reference to the stack frame that won't be changed when I create an external variable.
I'm using the following code to do this:
int some_variadic_function(int n, ...)
{
__asm__("movl %rax, %rbp");
return 0;
}
int main() {
some_variadic_function(3, 1, 2, 3);
return 0;
}
However, when I try and compile this with clang I get the following error:
using_rbp.c:4:13: error: invalid operand for instruction
__asm__("movl %rax, %rbp");
^
<inline asm>:1:7: note: instantiated into assembly here
movl %rax, %rbp
^~~~~
1 error generated.
This seems to be implying that I can't put %rbp
directly into %rax
. Is that's what happening, or is there another issue with this code?
For reference, I'm on Mac with x86-64
hardware.
You have made a whole bunch of mistakes. Let's take them one by one:
In AT&T assembly syntax for x86, if you provide a size suffix on the instruction, it must match the sizes inferred from the operands. Size suffixes are almost always unnecessary for x86 (the only case I can think of, offhand, where they're needed is when the source operand is an immediate value and the destination is memory): I recommend leaving them out unless the assembler complains about their absence.
In AT&T assembly syntax, the destination comes second; mov %rax, %rbp
copies RAX into RBP, not the other way around.
In GNU-style inline assembly, %
begins an escape sequence (like in printf
); to write a literal register name you have to double the percent sign. This is why you are getting an error from clang, rather than from the assembler.
GNU-style inline assembly must be annotated with "operand constraints" so the compiler understands what you are doing. You cannot simply move a value into RAX and expect that to become the return value. See https://gcc.gnu.org/onlinedocs/gcc-11.3.0/gcc/Using-Assembly-Language-with-C.html -- read all of this manual section, not just the summary page I linked to.
In the 64-bit System V ABI for x86, %rbp
is an ordinary general-purpose register, not a "frame pointer".
The correct way to do what you were trying to do is
long some_variadic_function(int n, ...)
{
long rv;
__asm__("mov %%rbp, %0" : "=r" (rv));
return rv;
}
However, this must be compiled with -fno-omit-frame-pointer
or the return value will be garbage.
You are probably suffering from the infamous XY problem. Ask a new question about the thing you were originally trying to do, not about the details of your attempted solution to the problem, and we can probably be more helpful.