PR ld/14464
authorAlan Modra <amodra@gmail.com>
Fri, 31 Aug 2012 02:42:57 +0000 (02:42 +0000)
committerAlan Modra <amodra@gmail.com>
Fri, 31 Aug 2012 02:42:57 +0000 (02:42 +0000)
* elf64-ppc.c (ppc64_elf_relocate_section): Map symbols defined
by a linker script in .opd to corresponding input .opd section.

bfd/ChangeLog
bfd/elf64-ppc.c

index 3ec6b2f..a26977d 100644 (file)
@@ -1,3 +1,9 @@
+2012-08-31  Alan Modra  <amodra@gmail.com>
+
+       PR ld/14464
+       * elf64-ppc.c (ppc64_elf_relocate_section): Map symbols defined
+       by a linker script in .opd to corresponding input .opd section.
+
 2012-08-28  Maciej W. Rozycki  <macro@codesourcery.com>
 
        * elf32-ppc.c (ppc_elf_relocate_section): Assert that dynindx is
index 71403c3..27574b9 100644 (file)
@@ -12328,6 +12328,33 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                                   unresolved_reloc, warned);
          sym_name = h_elf->root.root.string;
          sym_type = h_elf->type;
+         if (sec != NULL
+             && sec->owner == output_bfd
+             && strcmp (sec->name, ".opd") == 0)
+           {
+             /* This is a symbol defined in a linker script.  All
+                such are defined in output sections, even those
+                defined by simple assignment from a symbol defined in
+                an input section.  Transfer the symbol to an
+                appropriate input .opd section, so that a branch to
+                this symbol will be mapped to the location specified
+                by the opd entry.  */
+             struct bfd_link_order *lo;
+             for (lo = sec->map_head.link_order; lo != NULL; lo = lo->next)
+               if (lo->type == bfd_indirect_link_order)
+                 {
+                   asection *isec = lo->u.indirect.section;
+                   if (h_elf->root.u.def.value >= isec->output_offset
+                       && h_elf->root.u.def.value < (isec->output_offset
+                                                     + isec->size))
+                     {
+                       h_elf->root.u.def.value -= isec->output_offset;
+                       h_elf->root.u.def.section = isec;
+                       sec = isec;
+                       break;
+                     }
+                 }
+           }
        }
       h = (struct ppc_link_hash_entry *) h_elf;