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.

© Marco Vanotti 2024

Powered by Hugo & new.css.