Re: Fw: Incorrect relocation info with -emit-relocs

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

Re: Fw: Incorrect relocation info with -emit-relocs

Alan Modra
On Thu, Dec 29, 2005 at 06:14:10PM +0200, Yaakov Yaari wrote:
> Hi Alan,
> The following mail was bounced back from binutils due to "552 spam score
> exceeded threshold"

Hmm, let's see if this reply makes it past the spam filters..

> ----- Forwarded by Yaakov Yaari/Haifa/IBM on 29/12/05 18:12 -----
> With GCC4.1/LD 2.16.91 20050923 for a C++ program I encountered mismatch
> between the an address stored in .ctors section and the relocation attached
> to that address.
>
> The location in the .ctors is 1007d2a0
>
> Relocation section '.rela.ctors' at offset 0xc8f20 contains 123 entries:
>     Offset             Info             Type               Symbol's Value
> Symbol's Name + Addend
> 000000001007d008  0000001e00000026 R_PPC64_ADDR64         000000001007edb8
> .opd + d8
> 000000001007d010  0000001e00000026 R_PPC64_ADDR64         000000001007edb8
> .opd + 138
> 000000001007d018  0000001e00000026 R_PPC64_ADDR64         000000001007edb8
> .opd + 210
> ....
> 000000001007d2a0  0000001e00000026 R_PPC64_ADDR64         000000001007edb8
> .opd + 5550
>
> Hex dump of section '.ctors':
>   0x1007d000 ffffffff ffffffff 00000000 1007ee90 ................
>   0x1007d010 00000000 1007eef0 00000000 1007efc8 ................
> ...
>   0x1007d2a0 00000000 100842d8 00000000 100843c8 ......B.......C.
>
> >From the relocation info, 1007d2a0  should contain 1007edb8 + 5550 =
> 10084308
> whereas the actual address there is 100842d8
>
> The symbol table for the above addresses shows:
>   1629: 00000000100842d8    56 FUNC    LOCAL  DEFAULT   30
> _GLOBAL__I__ZN9mrPolygonC2ERK9ggPolygon
>   3899: 0000000010084308  1500 FUNC    GLOBAL DEFAULT   30
> _ZN9mrPolygonC2ERK9ggPolygon

This patch should fix the problem, and a similar serious bug with
powerpc64-linux ld -r.  When editing .opd, relocs against the .opd
section symbol (such as for function pointers) did not have their
addends adjusted for any .opd deletions.  When fixing this, I noticed
that some of the calculations involving branches were not keeping track
of addends properly.  Not usually a problem, because the addends are
typically zero.

        * elf64-ppc.c (ppc64_elf_relocate_section): Adjust relocs against
        opd section sym when opd has been edited.  Use correct addend
        when determining branch 'y' bit and branch overflow.  Adjust and
        save opd relocs for ld -r too.

Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.228
diff -u -p -r1.228 elf64-ppc.c
--- bfd/elf64-ppc.c 13 Dec 2005 05:39:34 -0000 1.228
+++ bfd/elf64-ppc.c 31 Dec 2005 07:25:01 -0000
@@ -9550,9 +9550,6 @@ ppc64_elf_relocate_section (bfd *output_
   /* Disabled until we sort out how ld should choose 'y' vs 'at'.  */
   bfd_boolean is_power4 = FALSE;
 
-  if (info->relocatable)
-    return TRUE;
-
   /* Initialize howto table if needed.  */
   if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
     ppc_howto_init ();
@@ -9574,7 +9571,7 @@ ppc64_elf_relocate_section (bfd *output_
   for (; rel < relend; rel++)
     {
       enum elf_ppc64_reloc_type r_type;
-      bfd_vma addend;
+      bfd_vma addend, orig_addend;
       bfd_reloc_status_type r;
       Elf_Internal_Sym *sym;
       asection *sec;
@@ -9611,6 +9608,7 @@ ppc64_elf_relocate_section (bfd *output_
       sym_name = NULL;
       unresolved_reloc = FALSE;
       warned = FALSE;
+      orig_addend = rel->r_addend;
 
       if (r_symndx < symtab_hdr->sh_info)
  {
@@ -9629,11 +9627,25 @@ ppc64_elf_relocate_section (bfd *output_
       if (adjust == -1)
  relocation = 0;
       else
- relocation += adjust;
+ {
+  /* If this is a relocation against the opd section sym
+     and we have edited .opd, adjust the reloc addend so
+     that ld -r and ld --emit-relocs output is correct.
+     If it is a reloc against some other .opd symbol,
+     then the symbol value will be adjusted later.  */
+  if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+    rel->r_addend += adjust;
+  else
+    relocation += adjust;
+ }
     }
+  if (info->relocatable)
+    continue;
  }
       else
  {
+  if (info->relocatable)
+    continue;
   RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
    r_symndx, symtab_hdr, sym_hashes,
    h_elf, sec, relocation,
@@ -10126,8 +10138,9 @@ ppc64_elf_relocate_section (bfd *output_
       && get_opd_info (sec) != NULL)
     {
       /* The branch destination is the value of the opd entry. */
-      bfd_vma off = (relocation - sec->output_section->vma
-     - sec->output_offset + rel->r_addend);
+      bfd_vma off = (relocation + addend
+     - sec->output_section->vma
+     - sec->output_offset);
       bfd_vma dest = opd_entry_value (sec, off, NULL, NULL);
       if (dest != (bfd_vma) -1)
  {
@@ -10143,7 +10156,7 @@ ppc64_elf_relocate_section (bfd *output_
   + input_section->output_section->vma);
 
   if (stub_entry == NULL
-      && (relocation + rel->r_addend - from + max_br_offset
+      && (relocation + addend - from + max_br_offset
   >= 2 * max_br_offset)
       && r_type != R_PPC64_ADDR14_BRTAKEN
       && r_type != R_PPC64_ADDR14_BRNTAKEN)
@@ -10177,7 +10190,7 @@ ppc64_elf_relocate_section (bfd *output_
       else
  {
   /* Invert 'y' bit if not the default.  */
-  if ((bfd_signed_vma) (relocation + rel->r_addend - from) < 0)
+  if ((bfd_signed_vma) (relocation + addend - from) < 0)
     insn ^= 0x01 << 21;
  }
 
@@ -10191,7 +10204,7 @@ ppc64_elf_relocate_section (bfd *output_
    && h->elf.root.type == bfd_link_hash_undefweak
    && r_type == R_PPC64_REL24
    && relocation == 0
-   && rel->r_addend == 0)
+   && addend == 0)
     {
       bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
       continue;
@@ -10300,7 +10313,7 @@ ppc64_elf_relocate_section (bfd *output_
   }
 
  for (; ent != NULL; ent = ent->next)
-  if (ent->addend == rel->r_addend
+  if (ent->addend == orig_addend
       && ent->owner == input_bfd
       && ent->tls_type == tls_type)
     break;
@@ -10335,7 +10348,7 @@ ppc64_elf_relocate_section (bfd *output_
     outrel.r_offset = (got->output_section->vma
        + got->output_offset
        + off);
-    outrel.r_addend = rel->r_addend;
+    outrel.r_addend = addend;
     if (tls_type & (TLS_LD | TLS_GD))
       {
  outrel.r_addend = 0;
@@ -10348,7 +10361,7 @@ ppc64_elf_relocate_section (bfd *output_
     bfd_elf64_swap_reloca_out (output_bfd,
        &outrel, loc);
     outrel.r_offset += 8;
-    outrel.r_addend = rel->r_addend;
+    outrel.r_addend = addend;
     outrel.r_info
       = ELF64_R_INFO (indx, R_PPC64_DTPREL64);
   }
@@ -10386,7 +10399,7 @@ ppc64_elf_relocate_section (bfd *output_
    emitting a reloc.  */
  else
   {
-    relocation += rel->r_addend;
+    relocation += addend;
     if (tls_type == (TLS_TLS | TLS_LD))
       relocation = 1;
     else if (tls_type != 0)
@@ -10439,7 +10452,7 @@ ppc64_elf_relocate_section (bfd *output_
     {
       struct plt_entry *ent;
       for (ent = h->elf.plt.plist; ent != NULL; ent = ent->next)
- if (ent->addend == rel->r_addend
+ if (ent->addend == orig_addend
     && ent->plt.offset != (bfd_vma) -1)
   {
     relocation = (htab->plt->output_section->vma
@@ -10885,7 +10898,7 @@ ppc64_elf_relocate_section (bfd *output_
       if (!((*info->callbacks->reloc_overflow)
     (info, (h ? &h->elf.root : NULL), sym_name,
      ppc64_elf_howto_table[r_type]->name,
-     rel->r_addend, input_bfd, input_section, rel->r_offset)))
+     orig_addend, input_bfd, input_section, rel->r_offset)))
  return FALSE;
     }
   else
@@ -10908,7 +10921,7 @@ ppc64_elf_relocate_section (bfd *output_
      adjusted.  Worse, reloc symbol indices will be for the output
      file rather than the input.  Save a copy of the relocs for
      opd_entry_value.  */
-  if (is_opd && info->emitrelocations)
+  if (is_opd && (info->emitrelocations || info->relocatable))
     {
       bfd_size_type amt;
       amt = input_section->reloc_count * sizeof (Elf_Internal_Rela);

--
Alan Modra
IBM OzLabs - Linux Technology Centre