This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug target/57583] New: large switches with jump tables are horribly broken on m68k


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57583

            Bug ID: 57583
           Summary: large switches with jump tables are horribly broken on
                    m68k
           Product: gcc
           Version: 4.8.1
            Status: UNCONFIRMED
          Severity: major
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: mikpe at it dot uu.se

Created attachment 30288
  --> http://gcc.gnu.org/bugzilla/attachment.cgi?id=30288&action=edit
test case and generator program

Switch jump tables on m68k-linux use 16-bit PC-relative offsets.  No
verification is made that the offsets actually fit in 16 bits, instead they are
silently truncated.  As a result, a large switch may branch to a wrong address;
in my case it branches into the jump table itself causing a SIGILL.

There are two bugs here:

1. GCC seems to hard-code the use of 16-bit offsets in its jump tables on
m68k-linux.  It should have an option to use 32-bit offsets instead.

2. GAS (not part of GCC I know) truncates ".word" operands to 16 bits without
warning or error when significant bits are lost.  I'll file that separately at
the sourceware/binutils bugzilla.

The test case contains a for (;;) loop with a switch () with 64K cases 0 ..
64K-1, each case containing a function call and a break. That switch becomes
the following assembly code on m68k-linux with gcc-4.8.1:

.L259:
        move.l (%a2),-(%sp)
        move.l %a2,-(%sp)
        jsr fetch
        addq.l #8,%sp
        and.l #65535,%d0
        move.w .L262(%pc,%d0.l*2),%d0
        jmp %pc@(2,%d0:w)
        .balignw 2,0x284c
.L262:
        .word .L260-.L262
        (64K - 1 more of these with varying labels in the first operand)

When run on the target the code SIGILLs:

0x80000402 in fetch ()
1: x/i $pc
=> 0x80000402 <fetch+14>:       rts
(gdb)
0x80001c0c in loop ()
1: x/i $pc
=> 0x80001c0c <loop+20>:        addql #8,%sp
(gdb)
0x80001c0e in loop ()
1: x/i $pc
=> 0x80001c0e <loop+22>:        andil #65535,%d0
(gdb)
0x80001c14 in loop ()
1: x/i $pc
=> 0x80001c14 <loop+28>:        movew %pc@(0x80001c1c <loop+36>,%d0:l:2),%d0
(gdb)
0x80001c18 in loop ()
1: x/i $pc
=> 0x80001c18 <loop+32>:        jmp %pc@(0x80001c1c <loop+36>,%d0:w)
(gdb) print $d0
$3 = 4

*** THIS "4" SHOWS THAT THE JUMP TABLE ENTRY HAS BEEN TRUNCATED

(gdb) stepi
0x80001c20 in loop ()
1: x/i $pc
=> 0x80001c20 <loop+40>:        .short 0xfff2
(gdb) stepi

Program received signal SIGILL, Illegal instruction.

I'm attaching the test case (bug.c) and the program used to generate it
(genbug.c).

Classifying as a target bug since the code works on x86_64 and powerpc64.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]