This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
MIPS md_apply_fix()(?) problem.
- From: cgd at broadcom dot com
- To: rsandifo at redhat dot com,binutils at sources dot redhat dot com
- Date: 15 Nov 2001 17:30:52 -0800
- Subject: MIPS md_apply_fix()(?) problem.
So, I ran across a rather serious problem, which i believe is caused
by Richard S's change:
2001-08-03 Richard Sandiford <rsandifo@redhat.com>
* config/tc-mips.c (md_apply_fix): Don't subtract the symbol value
from GPREL addends.
The test case below assembles incorrectly with that change. (If you
read the test, you end up thinking "WTF?!?!?!" that's unrelated!!!
but read on! FYI, this test case is distilled from assembly code
generated compiling a mips linux kernel w/ gcc 3.0.1.)
Assemble it with mips-{elf,linux}-as -o foo.o foo.s; it's that easy. 8-)
Before that change, you get:
0: 3c050000 lui a1,0x0
0: R_MIPS_HI16 boot_mem_map
4: 00b12821 addu a1,a1,s1
8: 8ca5000c lw a1,12(a1)
8: R_MIPS_LO16 boot_mem_map
c: 00000000 nop
After you get:
0: 3c050000 lui a1,0x0
0: R_MIPS_HI16 boot_mem_map
4: 00b12821 addu a1,a1,s1
8: 8ca50010 lw a1,16(a1)
8: R_MIPS_LO16 boot_mem_map
c: 00000000 nop
Note the 12 -> 16 you get in the instruction @ 0x8. This is the
offset of "boot_mem_map" in .bss in the object file produced by
assembling this source. (If you then go on to final link, it still
produces a value off by the same offset, in this example 4.)
I went back and debugged this in the 08-03 sources, and what I found
is described below. I don't get all of the way frags and relocs are
handled, so some of this may be ... way wrong, but please bear with
me. 8-)
What I believe is happening here is that code code is generated by the
"ld_st" code in tc-mips.c, which generates, from the comment:
If we have a base register, and this is a reference to a
GP relative symbol, we want
addu $tempreg,$breg,$gp
<op> $treg,<sym>($tempreg) (BFD_RELOC_MIPS_GPREL)
Otherwise we want
lui $tempreg,<sym> (BFD_RELOC_HI16_S)
addu $tempreg,$tempreg,$breg
<op> $treg,<sym>($tempreg) (BFD_RELOC_LO16)
This is set up via a rs_machine_dependent/RELAX_ENCODEd frag_var().
Anyway, md_estimate_size_before_relax says "take the second option",
and md_convert_frag frobs the instructions.
However, when md_apply_fix and tc_gen_reloc are invoked, the 'fixp'
they're given is still of type BFD_RELOC_GPREL16. (I don't understand
how/if the operations on it touch the 'right' address, but I think
they somehow do. anyway...)
>From looking at the code, it looks like the relocs won't be emitted
for code in the variant frags. and, in the case of the RELAX_ENCODE /
md_convert_frag handling, even if they were generated that
md_convert_frag doesn't try to discard relocs for the discarded code,
and instead use the ones for the replacement code.
So, all of this leads me to believe that the _only_ time you can
use the RELAX_ENCODE magic is when the two types of relocs in the
different parts of the variant frag are handled 'the same'. In this
case (and in many others throughout the tc-mips.c!!!) since GPREL and
LO16 relocs are no longer treated the same, the RELAX_ENCODE magic
doesn't work properly.
I have _no_ idea how the reloc on the lui is supposed to be handled
properly (is handled properly, it seems), but it definitely looks like
the LO16 reloc is being treated like a GPREL instead...
Thoughts? "HELP!!!!"
chris
===
.text
.ent fn # unneeded
.type fn,@function # unneeded
fn: # unneeded
lw $5,boot_mem_map+12($17)
.end fn # unneeded
.data
.align 2
spacer:
.space 4
.globl boot_mem_map
boot_mem_map:
.space 4