https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78176
Bug ID: 78176 Summary: [MIPS] miscompiles ldxc1 with large pointers on 32-bits Product: gcc Version: 6.2.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: target Assignee: unassigned at gcc dot gnu.org Reporter: james410 at cowgill dot org.uk Target Milestone: --- Created attachment 39937 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=39937&action=edit testcase Originally from the 'flint' package on Debian failing to build: https://buildd.debian.org/status/fetch.php?pkg=flint&arch=mipsel&ver=2.5.2-10&stamp=1477705959 The attached testcase when compiled and run on a 64-bit mips processor crashes with a SIGBUS error. The same binary works when run on a 32-bit mips processor. Compile with -O2 optimization like this: > gcc -O2 -march=mips32r2 ldxc1.c -o ldxc1 The crash occurs at the ldxc1 instruction at the end of this exerpt from the inner loop in the ldxc1_test function: > 8e0: 02028023 subu s0,s0,v0 > 8e4: afbf003c sw ra,60(sp) > 8e8: 0080b025 move s6,a0 > 8ec: 8fb3005c lw s3,92(sp) > [loop begins here] > 8f0: 02e0a825 move s5,s7 > 8f4: 26d6ffff addiu s6,s6,-1 > 8f8: 0256102a slt v0,s2,s6 > 8fc: 10400012 beqz v0,948 <ldxc1_test+0xd8> > 900: 8f998054 lw t9,-32684(gp) > 904: 8e620000 lw v0,0(s3) > 908: 8ea6fff8 lw a2,-8(s5) > 90c: 8ee30000 lw v1,0(s7) > 910: 00551021 addu v0,v0,s5 > 914: 26b5fffc addiu s5,s5,-4 > 918: 00511021 addu v0,v0,s1 > 91c: 00c33023 subu a2,a2,v1 > 920: 8c420000 lw v0,0(v0) > 924: 00541021 addu v0,v0,s4 > 928: 2694fff8 addiu s4,s4,-8 > 92c: 4e020301 ldxc1 $f12,v0(s0) Before the ldxc1 instruction is executed, gdb reports that the values in v0 and s0 are both large integers (above 0x80000000): (gdb) print/x $v0 $1 = 0xfffee7f8 (gdb) print/x $s0 $2 = 0x80008b50 When added together, the lower 32-bits contains the correct pointer (in this case on the stack). On a 32-bit processor this is fine. On a 64-bit processor, we know that v0 and s0 are sign extended as the last instructions to touch them were the addu at 924 and the subu at 8e0. So the values in the registers are actually: v0 = 0xfffffffffffee7f8 s0 = 0xffffffff80008b50 Adding these together (modulo 64-bit) gives the final pointer of 0xffffffff7fff7348 which is outside the user address space and thus results in a SIGBUS. I think GCC is assuming that the address calculated by the ldxc1 instruction is modulo 32-bit when compiled for a 32-bit processor. However, this is not true if the code is later run on a 64-bit processor.