ElBlo
Be careful with Inline ASM memory arguments!
Beware when you are writing inline assembly: if you clobber a register that cannot be clobbered (stack frame, stack pointer), you have to be careful while using memory arguments, as the compiler could use these registers to reference them, without knowing that you have modified them.
See this example:
void bar(void) {
__builtin_trap();
}
void foo(int n) {
asm volatile(
"subq $8, %%rsp\n"
"call *%[bar]\n"
:
:[bar] "rm"(bar)
:
);
}
Basically, a function that modifies the stack pointer and makes a call to a memory operand. Compiling this with clang generates the following output:
bar: ; @bar()
ud2
foo: ; @foo(int)
mov qword ptr [rsp - 8], offset bar()
sub rsp, 8
call qword ptr [rsp - 8]
ret
As you can see, the value is stored and loaded from rsp - 8
, but rsp
is
modified in-between. It might work at first, but it could break at any moment
if the compiler changes how it performs its addressing.
This might seem obvious, but it is easy to miss.