PATCH: Re: 971225: bootstrap fails on powerpc-unknown-linux-gnu*
Geoffrey KEATING
geoffk@discus.anu.edu.au
Thu Jan 29 19:57:00 GMT 1998
> Date: Fri, 30 Jan 1998 09:23:30 +1100 (EST)
> From: Franz Sirl <Franz.Sirl-kernel@lauterbach.com>
> the reported bootstrap fail on Linux/PPC was introduced in rev. 1.3 of
> rs6000/sysv4.h by a #undef JUMP_TABLES_IN_TEXT_SECTION. linux.h includes
> sysv4.h but didn't override the change.
> Eventually this hides a bug in binutils?
OK. I see what has happened.
The problem is the ever-popular 'switch folding' problem. At present,
egcs doesn't properly fold switch statements on powerpc. Normally
[ie. in egcs 1.0.1], switch statements look like this:
# load the address of the jump table
addis 9,0,.L3580@ha
addi 9,9,.L3580@l
# add an offset (calculated earlier from the index to the 'switch'),
# load it into the count register & jump.
lwzx 9,11,9
mtctr 9
bctr
# the actual table (in .text section, yuk!)
.L3580:
.long .Lsomething
.long .Lsomethingelse
.long .L3573
...
.L3573: some code
The JUMP_TABLES_IN_TEXT_SECTION change put the table in .rodata.
Now, when the 'offset' is constant, egcs partially folds the switch
statement, like this:
# load offset (not the offset of the offset :-)
addis 11,0,.L3573-.L3580@ha
addi 11,11,.L3573-.L3580@l
addis 9,0,.L3580@ha
addi 9,9,.L3580@l
addi 11,9,11
mtctr 9
bctr
# ... and generates a superfluous table, because it uses the label at
# the start :-(
.L3580:
.long .Lsomething
.long .Lsomethingelse
.long L3573
...
.L3573: some code
That used to be fine; the assembler knows where everything is, and can
calculate '.L3573-.L3580' at assembly time. But if the table is in
.rodata, the assembler doesn't know where .rodata is in relation to
the code, and ELF can't express the difference of two arbitrary
symbols; so the assembler complains, with possibly one of its less
clear error messages :-).
Certainly, egcs should put the jump tables in .rodata; this bit is
correct.
The general solution to this is to fix the switch folding. I don't
know enough about that part of gcc to do it. Any ideas?
If someone wants a shorter test case, you can see it in this:
void foo (char *s)
{
for (;;)
{
int t = 6;
switch (t)
{
case 2:
*s = '2';
case 6: case 4: case 3: case 1:
break;
}
}
}
which is the all-purpose test case for switch statement folding :-).
--
Geoff Keating <Geoff.Keating@anu.edu.au>
More information about the Gcc
mailing list