Retro68 icon indicating copy to clipboard operation
Retro68 copied to clipboard

A5 ignored on asm() register-clobber list

Open rhalkyard opened this issue 2 years ago • 2 comments

Given an asm() block such as:

void test_a5(void) {
    asm volatile(
        "clr.l %%a3\n\t"
        "clr.l %%a4\n\t"
        "clr.l %%a5\n\t"
        :
        :
        : "a3", "a4", "a5"
    );
}

Registers A3, A4, and A5 are marked as 'clobbered' and should be saved and restored. However, the generated code (from m68k-apple-macos-gcc -S a5test.c) preserves A3 and A4, but not A5:

test_a5:
        link.w %fp,#0
        move.l %a4,-(%sp)
        move.l %a3,-(%sp)
#APP
| 2 "a5test.c" 1
        clr.l %a3
        clr.l %a4
        clr.l %a5

| 0 "" 2
#NO_APP
        nop
        move.l (%sp)+,%a3
        move.l (%sp)+,%a4
        unlk %fp
        rts

I don't have a copy of mainline GCC 9 to test this against, but m68k GCC 13.2 does not exhibit this behavior, saving and restoring A5 correctly along with the others: https://godbolt.org/z/r5zese79j

I'm assuming that this is a side effect of modifying GCC to avoid using A5 due to its special nature on the Mac OS, but in this case it has the opposite effect!

rhalkyard avatar Dec 12 '23 16:12 rhalkyard

I should add, this is easy enough to work around by just 'manually' saving and restoring A5 in the assembly block, but it was definitely a fun issue to track down! Mostly just putting this here to document it - I wouldn't consider it a high priority to fix.

rhalkyard avatar Dec 12 '23 17:12 rhalkyard

That's an interesting... consequence.

I guess that %a5 is reserved as a fixed register, but it's not actually considered 'used', so it doesn't get saved & restored.

GCC seems to behave similarly on other platforms... on ARM, %x29 is the frame pointer, and....

int foo();

void useFramePointer()
{
   foo();
}

void clobberFramePointer()
{
    asm volatile(
        "add x29, x29, x29"
        : : : "x29"
    );
}

gives me

useFramePointer():
        stp     x29, x30, [sp, -16]!
        mov     x29, sp
        bl      foo()
        ldp     x29, x30, [sp], 16
        ret
clobberFramePointer():
        add x29, x29, x29
        ret

see godbolt

... in other words - it's carefully saving and restoring %x29 before it does a function call, but it does nothing to protect it from the asm statement.

So let's leave this ticket here as a warning until there's a piece of documentation that mentions it...

autc04 avatar Dec 12 '23 23:12 autc04