Thursday, February 3, 2022

[SOLVED] Confusion about different clobber description for arm inline assembly

Issue

I'm learning ARM inline assembly, and is confused about a very simple function: assign the value of x to y (both are int type), on arm32 and arm64 why different clobber description required?

Here is the code:

#include <arm_neon.h>
#include <stdio.h>

void asm_test()
{
    int x = 10;
    int y = 0;

#ifdef __aarch64__
    asm volatile(
        "mov %w[in], %w[out]"
        : [out] "=r"(y)
        : [in] "r"(x)
        : "r0" // r0 not working, but r1 or x1 works
    );
#else
    asm volattile(
        "mov %[in], %[out]"
        : [out] "=r"(y)
        : [in] "r"(x)
        : "r0"    // r0 works, but r1 not working
    );
#endif
    printf("y is %d\n", y);
}

int main() {
    arm_test();

    return 0;
}

Tested on my rooted android phone, for arm32, r0 generates correct result but r1 won't. For arm64, r1 or x1 generate correct result, and r0 won't. Why on arm32 and arm64 they are different? What is the concrete rule for this and where can I find it?


Solution

ARM / AArch64 syntax is mov dst, src.

Your asm statement only works if the compiler happens to pick the same register for both "=r" output and "r" input (or something like that, given extra copies of x floating around).

Different clobbers simply perturb the compiler's register-allocation choices. Look at the generated asm (gcc -S or on https://godbolt.org/, especially with -fverbose-asm.)

Undefined Behaviour from getting the constraints mismatched with the instructions in the template string can still happen to work; never assume that an asm statement is correct just because it works with one set of compiler options and surrounding code.



Answered By - Peter Cordes
Answer Checked By - Marilyn (WPSolving Volunteer)