Arush Agarampur
Arush Agarampur

Reputation: 1420

Inline assembly is not producing my desired result with clang

I am using inline assembly x86_64 with clang. I want the exact assembly compiled into my binary that I specify in my source code, but for some reason clang keeps on changing it. This only happens when I use AT&T GCC style assembly, this does not happen with MSVC __asm I want to use AT&T style assembly because the rest of my code uses AT&T style a lot and I want to keep things consistent. This is how my assembly code is declared:

__attribute__((naked)) void XxInternalOperation()
{
    asm volatile("mov %%rcx, %%rax\n\t"
        "mov %0, %%r11\n\t"
        "jmpq *%%r11"
        :
        : "r" (jumpAddrAbsolute)
        : "r11");
}

I want my assembly code to represent this intel code:

mov rax, rcx
mov r11, jmpAddrAbsolute ; <-- this is an unsigned long long variable
jmp r11

But a quick dissasembly in IDA shows something else:

mov rax, cs:jumpAddrAbsolute
mov rax, rcx
mov r11, rax
jmp r11

Is there a way to get the exact assembly code I want?

Upvotes: 1

Views: 929

Answers (1)

fuz
fuz

Reputation: 92966

Clang does not “change” your assembly. It does exactly what you ask it to do and that is: it picks a register (that's what the r constraint means) and substitutes %0 for it. Note that this register can also be rax in which case your code won't work. If you want clang to pick a memory operand, use the m constraint instead. Refer to the gcc manual for details on gcc-style inline assembly. Here's an example:

extern unsigned long long jumpAddrAbsolute;

__attribute__((naked)) void XxInternalOperation()
{
    asm volatile("mov %%rcx, %%rax\n\t"
        "mov %0, %%r11\n\t"
        "jmpq *%%r11"
        :
        : "m" (jumpAddrAbsolute)
        : "r11", "rax");
}

This compiles to:

movq    %rcx, %rax
movq    jumpAddrAbsolute(%rip), %r11
jmpq    *%r11

which seems what you want.

Note that I have marked rax as clobbered since you use it in the first instruction. Note further that there is no guarantee that rcx holds any particular value when this inline assembly statement is executed. The compiler is free to set it to whatever value it likes.

Note also that the compiler may possibly decide to inline XxInternalOperation in which case your indirect jump will have the unintended side effect of performing a tail call in the caller. Consider marking the function as noinline to avoid this scenario.

In general though, performing jumps or calls in inline assembly is often a sign of a wrong approach and usually leads to all sorts of problems. If you have some details about the problem that you have decided to solve using this inline assembly, I might be able to suggest a better solution to you.

Upvotes: 2

Related Questions