This is the mail archive of the binutils@sourceware.org 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]

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


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


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