* elf32-cris.c (cris_elf_plt_sym_val): Rewrite to work in presence
authorHans-Peter Nilsson <hp@axis.com>
Mon, 18 Jun 2012 06:16:59 +0000 (06:16 +0000)
committerHans-Peter Nilsson <hp@axis.com>
Mon, 18 Jun 2012 06:16:59 +0000 (06:16 +0000)
of merged .got and .got.plt entries.

bfd/ChangeLog
bfd/elf32-cris.c

index ad5228e..d4902da 100644 (file)
@@ -1,3 +1,8 @@
+2012-06-18  Hans-Peter Nilsson  <hp@axis.com>
+
+       * elf32-cris.c (cris_elf_plt_sym_val): Rewrite to work in presence
+       of merged .got and .got.plt entries.
+
 2012-06-18  John Szakmeister  <john@szakmeister.net>
 
        * elf32-arm.c (elf32_arm_final_link_relocate): Correct return value.
index 3710d47..58e430e 100644 (file)
@@ -2719,16 +2719,64 @@ cris_elf_gc_sweep_hook (bfd *abfd,
 /* The elf_backend_plt_sym_val hook function.  */
 
 static bfd_vma
-cris_elf_plt_sym_val (bfd_vma i, const asection *plt,
-                     const arelent *rel ATTRIBUTE_UNUSED)
+cris_elf_plt_sym_val (bfd_vma i ATTRIBUTE_UNUSED, const asection *plt,
+                     const arelent *rel)
 {
   bfd_size_type plt_entry_size;
+  bfd_size_type pltoffs;
+  bfd *abfd = plt->owner;
 
+  /* Same for CRIS and CRIS v32; see elf_cris_(|pic_)plt_entry(|_v32)[].  */
+  bfd_size_type plt_entry_got_offset = 2;
+  bfd_size_type plt_sec_size;
+  bfd_size_type got_vma_for_dyn;
+  asection *got;
+
+  /* FIXME: the .got section should be readily available also when
+     we're not linking.  */
+  if ((got = bfd_get_section_by_name (abfd, ".got")) == NULL)
+    return (bfd_vma) -1;
+
+  plt_sec_size =  bfd_section_size (plt->owner, plt);
   plt_entry_size
-    = (bfd_get_mach (plt->owner) == bfd_mach_cris_v32
+    = (bfd_get_mach (abfd) == bfd_mach_cris_v32
        ? PLT_ENTRY_SIZE_V32 : PLT_ENTRY_SIZE);
 
-  return plt->vma + (i + 1) * plt_entry_size;
+  /* Data in PLT is GOT-relative for DYN, but absolute for EXE.  */
+  got_vma_for_dyn = (abfd->flags & EXEC_P) ? 0 : got->vma;
+
+  /* Because we can have merged GOT entries; a single .got entry for
+     both GOT and the PLT part of the GOT (.got.plt), the index of the
+     reloc in .rela.plt is not the same as the index in the PLT.
+     Instead, we have to hunt down the GOT offset in the PLT that
+     corresponds to that of this reloc.  Unfortunately, we will only
+     be called for the .rela.plt relocs, so we'll miss synthetic
+     symbols for .plt entries with merged GOT entries.  (FIXME:
+     fixable by providing our own bfd_elf32_get_synthetic_symtab.
+     Doesn't seem worthwile at time of this writing.)  FIXME: we've
+     gone from O(1) to O(N) (N number of PLT entries) for finding each
+     PLT address.  Shouldn't matter in practice though.  */
+
+  for (pltoffs = plt_entry_size;
+       pltoffs < plt_sec_size;
+       pltoffs += plt_entry_size)
+    {
+      bfd_size_type got_offset;
+      bfd_byte gotoffs_raw[4];
+      
+      if (!bfd_get_section_contents (abfd, (asection *) plt, gotoffs_raw,
+                                    pltoffs + plt_entry_got_offset,
+                                    sizeof (gotoffs_raw)))
+       return (bfd_vma) -1;
+
+      got_offset = bfd_get_32 (abfd, gotoffs_raw);
+      if (got_offset + got_vma_for_dyn == rel->address)
+       return plt->vma + pltoffs;
+    }
+
+  /* While it's tempting to BFD_ASSERT that we shouldn't get here,
+     that'd not be graceful behavior for invalid input.  */
+  return (bfd_vma) -1;
 }
 
 /* Make sure we emit a GOT entry if the symbol was supposed to have a PLT