[Bug target/57583] New: large switches with jump tables are horribly broken on m68k
mikpe at it dot uu.se
gcc-bugzilla@gcc.gnu.org
Tue Jun 11 09:58:00 GMT 2013
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.
More information about the Gcc-bugs
mailing list