This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
powerpc64 multi-toc fix
- From: Alan Modra <amodra at bigpond dot net dot au>
- To: binutils at sources dot redhat dot com, Michal Ostrowski <mostrows at watson dot ibm dot com>
- Date: Tue, 12 Aug 2003 15:27:25 +0930
- Subject: powerpc64 multi-toc fix
The blather at the start here will make some sense to Michal, others can
just skip to the patch.
segfault at 0x100b9488, in __do_global_dtors_aux
r1 = 0x1ff7ffff420
r2 = 0x10542230 obviously bogus
caller r1 = 0x1ff7ffff4a0
return addr = 0x10456864 (in _fini) OK, as expected
_fini opd entry at 0x10504c60
10504c58 00000000 10456850
10504c68 00000000 105520a0 00000000 00000000 .....U .........
saved r2 = *(0x1ff7ffff4a0+40) = 0x105520a0 OK, matches .opd
call stub for __do_global_dtors_aux
10456840: f8 41 00 28 std r2,40(r1)
10456844: 3c 42 ff ff addis r2,r2,-1
10456848: 38 42 01 90 addi r2,r2,400
1045684c: 4b c6 2c 18 b 100b9464 <.__do_global_dtors_aux>
so we enter do_global_dtors_aux with r2 = 0x105520a0 - 0x10000 + 400
= 0x10542230, the bogus value.
=> the call stub is busted or something is screwy about where ld
thinks the toc is for _fini. Turns out is is the latter.
(gdb) p *((struct ppc_stub_hash_entry *) gen_entry)->stub_sec
$5 = {name = 0xad5385c ".fini.stub", id = 10359, index = 348,
[snip]
(gdb) p htab->stub_group[((struct ppc_stub_hash_entry *) gen_entry)->id_sec->id]
$7 = {link_sec = 0x817bfc4, stub_sec = 0x92c65a8, toc_off = 97904}
So ld thinks the call in _fini to do_global_dtors_aux has its toc at
97904.
(gdb) p ((struct ppc_stub_hash_entry *) gen_entry)->id_sec->owner->filename
$14 = 0xbffff0fe "./crti.o"
(gdb) p ((struct ppc_stub_hash_entry *) gen_entry)->id_sec->owner->sections->next->next->next->next->name
$19 = 0x817a3cc ".opd"
(gdb) p ((struct ppc_stub_hash_entry *) gen_entry)->id_sec->owner->sections->next->next->next->next->id
$20 = 38
(gdb) p htab->stub_group[38]
$21 = {link_sec = 0x0, stub_sec = 0x0, toc_off = 32768}
Yet the opd toc entry for _fini is at 32768. Oops. I've been caught
out by that horrible pasting we do of pieces of functions to make up
_init and _fini.
Fortunately, there's a neat trick we can use which allows the .opd
entries in a particular object file to have different toc bases.
* elf64-ppc.c (ppc64_elf_next_input_section): Update comment.
(ppc64_elf_relocate_section): For zero sym R_PPC64_TOC relocs,
use the function sym from the previous reloc.
Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.127
diff -u -p -r1.127 elf64-ppc.c
--- bfd/elf64-ppc.c 11 Aug 2003 14:26:10 -0000 1.127
+++ bfd/elf64-ppc.c 12 Aug 2003 05:44:08 -0000
@@ -6608,7 +6608,8 @@ ppc64_elf_next_input_section (struct bfd
/* If a code section has a function that uses the TOC then we need
to use the right TOC (obviously). Also, make sure that .opd gets
- the correct TOC value. */
+ the correct TOC value for R_PPC64_TOC relocs that don't have or
+ can't find their function symbol (shouldn't ever happen now). */
if (isec->has_gp_reloc || (isec->flags & SEC_CODE) == 0)
{
if (elf_gp (isec->owner) != 0)
@@ -7327,6 +7328,16 @@ ppc64_elf_relocate_section (bfd *output_
r_type = ELF64_R_TYPE (rel->r_info);
r_symndx = ELF64_R_SYM (rel->r_info);
+
+ /* For old style R_PPC64_TOC relocs with a zero symbol, use the
+ symbol of the previous ADDR64 reloc. The symbol gives us the
+ proper TOC base to use. */
+ if (rel->r_info == ELF64_R_INFO (0, R_PPC64_TOC)
+ && rel != relocs
+ && ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_ADDR64
+ && is_opd)
+ r_symndx = ELF64_R_SYM (rel[-1].r_info);
+
sym = NULL;
sec = NULL;
h = NULL;
--
Alan Modra
IBM OzLabs - Linux Technology Centre