Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A5 ignored on asm() register-clobber list #220

Open
rhalkyard opened this issue Dec 12, 2023 · 2 comments
Open

A5 ignored on asm() register-clobber list #220

rhalkyard opened this issue Dec 12, 2023 · 2 comments

Comments

@rhalkyard
Copy link
Contributor

rhalkyard commented Dec 12, 2023

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
Copy link
Contributor Author

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.

@autc04
Copy link
Owner

autc04 commented Dec 12, 2023

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...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants