Search code examples
cclanginline-assembly

Inline assembly reusing same register when it shouldn't


I have a bit scan function that uses inline assembly and clang is producing weird output.

Code:

uint64_t bit_scan_forward(uint64_t input) {
    uint64_t result;
    asm("MOVQ %[immidiate], %[result];"
        "BSF %[input], %[result];"
        :[result] "=r" (result)
        :[input] "r"  (input)
        ,[immidiate] "N" (64));
    return result;
}

Output:

sub  rsp, 0x10
mov  qword ptr [rsp+0x8], rcx
mov  rax, qword ptr [rsp+0x8] //set input
mov  rax, 0x40                //set result(which uses the same register as input for some reason)
bsf  rax, rax                 //do bsf
mov  qword ptr [rsp], rax
mov  rax, qword ptr [rsp]
add  rsp, 0x10
ret

It is mixing up the input and result registers, which produces a wrong result.

First time writing inline assembly, am I doing something wrong?

Is it not safe to assume that it will use different registers? If so. how do I tell it to use different registers?


Solution

  • clang follows the same rules for inline asm as gcc:

    Use the & constraint modifier (see Modifiers) on all output operands that must not overlap an input. Otherwise, GCC may allocate the output operand in the same register as an unrelated input operand, on the assumption that the assembler code consumes its inputs before producing outputs.