https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87733
--- Comment #16 from Rich Felker <bugdal at aerifal dot cx> ---
> I didn't say this very well... The only issue is using the same hard
> register for two different operands. You don't need to do this for
> syscalls (and you do not *need* that *ever*, of course).
I hit the bug without using the same hard register for two operands. At least
I'm pretty sure it's the same bug because the behavior matches and it's present
in 6.3.0 but not 9.2.0.
> Can you post some code that fails? If you think this is a GCC bug (in
> some older branch?) that we should fix, please open a new PR for it.
Here's the relevant code extracted out of musl:
#define SYSCALL_CLOBBERLIST \
"$1", "$3", "$11", "$12", "$13", \
"$14", "$15", "$24", "$25", "hi", "lo", "memory"
long syscall6(long n, long a, long b, long c, long d, long e, long f)
{
register long r4 __asm__("$4") = a;
register long r5 __asm__("$5") = b;
register long r6 __asm__("$6") = c;
register long r7 __asm__("$7") = d;
register long r8 __asm__("$8") = e;
register long r9 __asm__("$9") = f;
register long r2 __asm__("$2");
__asm__ __volatile__ (
"subu $sp,$sp,32 ; sw $8,16($sp) ; sw $9,20($sp) ; "
"addu $2,$0,%4 ; syscall ;"
"addu $sp,$sp,32"
: "=&r"(r2), "+r"(r7), "+r"(r8), "+r"(r9)
: "ir"(n), "r"(r4), "r"(r5), "r"(r6)
: SYSCALL_CLOBBERLIST, "$10");
return r7 && r2>0 ? -r2 : r2;
}
Built with gcc 6.3.0, %4 ends up expanding to $2, violating the earlyclobber,
and %0 gets bound to $16 rather than $2 (which is why the violation is allowed,
it seems).
With "0"(r2) added to input constraints, the bug goes away.
I don't particularly think this bug is something that needs to be fixed in
older branches, especially if doing so is hard, but I do think it's something
we need a solid reliable workaround for.