This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
sh-elf: the substraction of two symbols
- To: binutils at sources dot redhat dot com
- Subject: sh-elf: the substraction of two symbols
- From: kaz Kojima <kkojima at rr dot iij4u dot or dot jp>
- Date: Sat, 06 Jan 2001 09:40:15 +0900
Hi,
I have a problem with the sh-elf toolchain. Current as/ld for sh-elf
doesn't handle the substraction of two symbols correctly, if these
two symbols are in different sections.
For example, foo.s
.little
.text
.align 5
f:
rts
nop
.section .text.foo,"aw",@progbits
.align 5
.global ff
ff:
nop
nop
nop
nop
L:
rts
nop
.align 2
.long f-L ! <- This
is assembled to foo.o:
Disassembly of section .text
[snip]
Disassembly of section .text.foo:
00000000 <ff>:
0: 09 00 .word 0x0900
2: 09 00 .word 0x0900
4: 09 00 .word 0x0900
6: 09 00 .word 0x0900
00000008 <L>:
8: 0b 00 .word 0x0b00
a: 09 00 .word 0x0900
c: f8 ff .word 0xf8ff
e: ff ff .word 0xffff
and readelf shows that there is a relocation
Relocation section '.rela.text.foo' at offset 0x2a8 contains 1 entries:
Offset Info Type Symbol's Value Symbol's Name Addend
0000000c 00102 R_SH_REL32 00000000 .text + 0
Then ld -EL outputs the following result from foo.o:
Disassembly of section .text:
00000340 <f>:
340: 0b 00 rts
342: 09 00 nop
...
00000360 <ff>:
360: 09 00 nop
362: 09 00 nop
364: 09 00 nop
366: 09 00 nop
00000368 <L>:
368: 0b 00 rts
36a: 09 00 nop
36c: d4 ff .word 0xffd4
36e: ff ff .word 0xffff
and there is no relocation at 0x36c.
Here we get 0xffffffd4 in the word at 0x36c instead of
f - L = 0x340 - 0x368 = 0xffffffd8.
The relocation type R_SH_REL32 wants the relocation by
(the value of symbol) - (the position of object) + (the value of reloc)
and in the above case, this is
f (== .text) - (L + 4) + (the value of reloc). So the value of
reloc must to be 4 in foo.o. It seems that we need a hack in
md_apply_fix like i386 backend does for BFD_RELLOC_32_PCREL in
md_apply_fix3 to get correct in-place relocation.
The second point is that sh-elf ld ignores in-place relocation
for R_SH_REL32, though it seems the assembler gives in-place value
for this type of relocation.
One more another problem occurs when generating a relocateable object
from multiple objects which include R_SH_REL32 relocations for the
section symbol. An simple example can be get from a.s
.text
nop
nop
nop
nop
and ld -EL -r -o afoo.ro a.o foo.o.
The linker applies _bfd_final_link_relocate in sh_elf_relocate_section
to wind up the relocation from foo.o since the symbol f becomes not
equal to .text in the output section.
But _bfd_final_link_relocate treats pc_rel relocations specially
which is wrong operation in this case. It seems that we have to call
_bfd_relocate_contents directly.
Under these changes, the results of small tests looks good and some
shared libraries which didn't work can run in sh-linux now.
But I suspect that these changes may break something. Anyway, I'd
like to append my patch to clarify my point.
Thoughts?
kaz
--
--- cvs/src/gas/config/tc-sh.c Sat Nov 18 00:50:50 2000
+++ binutils-current/gas/config/tc-sh.c Tue Nov 28 06:57:47 2000
@@ -2779,6 +2779,11 @@
&& fixP->fx_addsy != NULL
&& S_IS_WEAK (fixP->fx_addsy))
val -= S_GET_VALUE (fixP->fx_addsy);
+
+ if (OUTPUT_FLAVOR == bfd_target_elf_flavour
+ && fixP->fx_r_type == BFD_RELOC_32_PCREL
+ && fixP->fx_addsy != NULL)
+ val += fixP->fx_where + fixP->fx_frag->fr_address;
#endif
#ifndef BFD_ASSEMBLER
--- cvs/src/bfd/elf32-sh.c Sun Nov 12 00:50:20 2000
+++ binutils-current/bfd/elf32-sh.c Mon Jan 1 12:10:57 2001
@@ -120,8 +120,8 @@
complain_overflow_signed, /* complain_on_overflow */
sh_elf_ignore_reloc, /* special_function */
"R_SH_REL32", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
+ true, /* partial_inplace */
+ 0xffffffff, /* src_mask */
0xffffffff, /* dst_mask */
true), /* pcrel_offset */
@@ -2940,7 +2940,11 @@
section symbol winds up in the output section. */
sym = local_syms + r_symndx;
if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
- goto final_link_relocate;
+ {
+ r = _bfd_relocate_contents (howto, input_bfd, relocation,
+ contents + rel->r_offset);
+ goto relocation_done;
+ }
continue;
}
@@ -3331,6 +3335,7 @@
}
}
+ relocation_done:
if (r != bfd_reloc_ok)
{
switch (r)