[Bug target/78176] New: [MIPS] miscompiles ldxc1 with large pointers on 32-bits

james410 at cowgill dot org.uk gcc-bugzilla@gcc.gnu.org
Tue Nov 1 12:35:00 GMT 2016


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.


More information about the Gcc-bugs mailing list