This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]