[Proposed patch] Huge performance regression in ld -r since binutils >= 2.21

Alan Modra amodra@gmail.com
Mon Nov 9 02:16:00 GMT 2015


On Fri, Nov 06, 2015 at 05:22:56PM +0100, Romain Geissler wrote:
> When we create the first level module1.o and module2.o, everything works
> fine. ld -r last less than 10s. However, that creates huges .o files,
> having huge debug sections with millions of relocs. Later when we build
> module3.o from module1.o and module2.o, since the memmove happens on huge
> relocs array, ld end up consuming 100% CPU for minutes. With binutils
> 2.25.1 one single link operation lasts more than 5 minutes, compared to
> 10s with ld 2.20.

I've been telling people for at least 10 years not to use ld -r as a
packaging tool, so I'm tempted to say this as a good result..

> I have a proposal of patch to fix that, see the patch attached. Note that
> I know it only works for x86/x64 and that it will break other targets, I
> just want to make sure you agree on the idea of the fix. To fix this
> performance issue, I choose to have two iterators:

The idea is good, but the implementation horrible due to trying to
keep RELOC_AGAINST_DISCARDED_SECTION.  I think you should just throw
that away and start over.

Here for instance is what I'm testing on powerpc64, one of the more
complex targets to change given that powerpc emits relocs that match
edited code (TLS sequences and others) rather than just leaving the
original relocs.  I've replaced "rel" with "wrel" and "rrel".  The
rules are fairly simple:  Copy rrel[0] to wrel[0] at start of loop.
Use "wrel" as the pointer for negative or zero index array
dereferencing, "rrel" for positive.  If restarting current reloc
processing, as done by powerpc after changing the symbol, then copy
wrel[0] back to rrel[0] (but optimised a little in most cases by
changing rrel[0] in the first place).

We should probably look into removing the "???" code below.  If that
was just to pass the ld-elf/linkonce1 test, I think the test should be
updated and an empty reloc section written.  Also, it would be nice to
discard relocs for more than just debug sections, but that would
require changes to elf-eh-frame.c.

	* elf64-ppc.c (ppc64_elf_relocate_section): Use read and write
	pointers to reloc array, rather than memmove when deleting a
	reloc.  Don't use RELOC_AGAINST_DISCARDED_SECTION.  Adjust
	reloc counts at end of loop.

diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index cda8e59..e6a3983 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -13161,7 +13161,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
   struct ppc_link_hash_table *htab;
   Elf_Internal_Shdr *symtab_hdr;
   struct elf_link_hash_entry **sym_hashes;
-  Elf_Internal_Rela *rel;
+  Elf_Internal_Rela *rrel;
+  Elf_Internal_Rela *wrel;
   Elf_Internal_Rela *relend;
   Elf_Internal_Rela outrel;
   bfd_byte *loc;
@@ -13193,9 +13194,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
   sym_hashes = elf_sym_hashes (input_bfd);
   is_opd = ppc64_elf_section_data (input_section)->sec_type == sec_opd;
 
-  rel = relocs;
+  rrel = wrel = relocs;
   relend = relocs + input_section->reloc_count;
-  for (; rel < relend; rel++)
+  for (; rrel < relend; wrel++, rrel++)
     {
       enum elf_ppc64_reloc_type r_type;
       bfd_vma addend;
@@ -13219,21 +13220,24 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       struct ppc_stub_hash_entry *stub_entry;
       bfd_vma max_br_offset;
       bfd_vma from;
-      const Elf_Internal_Rela orig_rel = *rel;
+      const Elf_Internal_Rela orig_rel = *rrel;
       reloc_howto_type *howto;
       struct reloc_howto_struct alt_howto;
 
-      r_type = ELF64_R_TYPE (rel->r_info);
-      r_symndx = ELF64_R_SYM (rel->r_info);
+      if (wrel != rrel)
+	*wrel = *rrel;
+
+      r_type = ELF64_R_TYPE (rrel->r_info);
+      r_symndx = ELF64_R_SYM (rrel->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
+      if (wrel->r_info == ELF64_R_INFO (0, R_PPC64_TOC)
+	  && wrel != relocs
+	  && ELF64_R_TYPE (wrel[-1].r_info) == R_PPC64_ADDR64
 	  && is_opd)
-	r_symndx = ELF64_R_SYM (rel[-1].r_info);
+	r_symndx = ELF64_R_SYM (wrel[-1].r_info);
 
       sym = NULL;
       sec = NULL;
@@ -13251,12 +13255,12 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	  sec = local_sections[r_symndx];
 	  sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, sec);
 	  sym_type = ELF64_ST_TYPE (sym->st_info);
-	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
+	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, wrel);
 	  opd = get_opd_info (sec);
 	  if (opd != NULL && opd->adjust != NULL)
 	    {
 	      long adjust = opd->adjust[OPD_NDX (sym->st_value
-						 + rel->r_addend)];
+						 + wrel->r_addend)];
 	      if (adjust == -1)
 		relocation = 0;
 	      else
@@ -13267,7 +13271,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 		     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;
+		    wrel->r_addend += adjust;
 		  else
 		    relocation += adjust;
 		}
@@ -13277,7 +13281,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	{
 	  bfd_boolean ignored;
 
-	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
+	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, wrel,
 				   r_symndx, symtab_hdr, sym_hashes,
 				   h_elf, sec, relocation,
 				   unresolved_reloc, warned, ignored);
@@ -13314,10 +13318,23 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       h = (struct ppc_link_hash_entry *) h_elf;
 
       if (sec != NULL && discarded_section (sec))
-	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
-					 rel, 1, relend,
-					 ppc64_elf_howto_table[r_type], 0,
-					 contents);
+	{
+	  _bfd_clear_contents (ppc64_elf_howto_table[r_type],
+			       input_bfd, input_section,
+			       contents + wrel->r_offset);
+	  wrel->r_info = 0;
+	  wrel->r_addend = 0;
+
+	  /* For ld -r, remove relocations in debug sections against
+	     sections defined in discarded sections.  Not done for
+	     non-debug to preserve relocs in .eh_frame which the
+	     eh_frame editing code expects to be present.  */
+	  if (bfd_link_relocatable (info)
+	      && (input_section->flags & SEC_DEBUGGING))
+	    wrel--;
+
+	  continue;
+	}
 
       if (bfd_link_relocatable (info))
 	continue;
@@ -13355,7 +13372,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	  unsigned char *toc_tls;
 
 	  if (!get_tls_mask (&toc_tls, &toc_symndx, &toc_addend,
-			     &local_syms, rel, input_bfd))
+			     &local_syms, wrel, input_bfd))
 	    return FALSE;
 
 	  if (toc_tls)
@@ -13385,7 +13402,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	      (!IS_PPC64_TLS_RELOC (r_type)
 	       ? _("%P: %H: %s used with TLS symbol `%T'\n")
 	       : _("%P: %H: %s used with non-TLS symbol `%T'\n"),
-	       input_bfd, input_section, rel->r_offset,
+	       input_bfd, input_section, wrel->r_offset,
 	       ppc64_elf_howto_table[r_type]->name,
 	       sym_name);
 	}
@@ -13409,13 +13426,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	  break;
 
 	case R_PPC64_LO_DS_OPT:
-	  insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset);
+	  insn = bfd_get_32 (output_bfd, contents + wrel->r_offset - d_offset);
 	  if ((insn & (0x3f << 26)) != 58u << 26)
 	    abort ();
 	  insn += (14u << 26) - (58u << 26);
-	  bfd_put_32 (output_bfd, insn, contents + rel->r_offset - d_offset);
+	  bfd_put_32 (output_bfd, insn, contents + wrel->r_offset - d_offset);
 	  r_type = R_PPC64_TOC16_LO;
-	  rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+	  wrel->r_info = ELF64_R_INFO (r_symndx, r_type);
 	  break;
 
 	case R_PPC64_TOC16:
@@ -13428,7 +13445,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	    int retval;
 
 	    retval = get_tls_mask (&toc_tls, &toc_symndx, &toc_addend,
-				   &local_syms, rel, input_bfd);
+				   &local_syms, wrel, input_bfd);
 	    if (retval == 0)
 	      return FALSE;
 
@@ -13467,10 +13484,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	  if (tls_mask != 0
 	      && (tls_mask & TLS_TPREL) == 0)
 	    {
-	      rel->r_offset -= d_offset;
-	      bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
+	      wrel->r_offset -= d_offset;
+	      bfd_put_32 (output_bfd, NOP, contents + wrel->r_offset);
 	      r_type = R_PPC64_NONE;
-	      rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+	      wrel->r_info = ELF64_R_INFO (r_symndx, r_type);
 	    }
 	  break;
 
@@ -13480,22 +13497,24 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	      && (tls_mask & TLS_TPREL) == 0)
 	    {
 	    toctprel:
-	      insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset);
+	      insn = bfd_get_32 (output_bfd,
+				 contents + wrel->r_offset - d_offset);
 	      insn &= 31 << 21;
 	      insn |= 0x3c0d0000;	/* addis 0,13,0 */
-	      bfd_put_32 (output_bfd, insn, contents + rel->r_offset - d_offset);
+	      bfd_put_32 (output_bfd, insn,
+			  contents + wrel->r_offset - d_offset);
 	      r_type = R_PPC64_TPREL16_HA;
 	      if (toc_symndx != 0)
 		{
-		  rel->r_info = ELF64_R_INFO (toc_symndx, r_type);
-		  rel->r_addend = toc_addend;
+		  rrel->r_info = ELF64_R_INFO (toc_symndx, r_type);
+		  rrel->r_addend = toc_addend;
 		  /* We changed the symbol.  Start over in order to
 		     get h, sym, sec etc. right.  */
-		  rel--;
+		  wrel--, rrel--;
 		  continue;
 		}
 	      else
-		rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+		wrel->r_info = ELF64_R_INFO (r_symndx, r_type);
 	    }
 	  break;
 
@@ -13503,26 +13522,27 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	  if (tls_mask != 0
 	      && (tls_mask & TLS_TPREL) == 0)
 	    {
-	      insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
+	      insn = bfd_get_32 (output_bfd, contents + wrel->r_offset);
 	      insn = _bfd_elf_ppc_at_tls_transform (insn, 13);
 	      if (insn == 0)
 		abort ();
-	      bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
+	      bfd_put_32 (output_bfd, insn, contents + wrel->r_offset);
 	      /* Was PPC64_TLS which sits on insn boundary, now
 		 PPC64_TPREL16_LO which is at low-order half-word.  */
-	      rel->r_offset += d_offset;
+	      wrel->r_offset += d_offset;
 	      r_type = R_PPC64_TPREL16_LO;
 	      if (toc_symndx != 0)
 		{
-		  rel->r_info = ELF64_R_INFO (toc_symndx, r_type);
-		  rel->r_addend = toc_addend;
+		  rrel->r_offset = wrel->r_offset;
+		  rrel->r_info = ELF64_R_INFO (toc_symndx, r_type);
+		  rrel->r_addend = toc_addend;
 		  /* We changed the symbol.  Start over in order to
 		     get h, sym, sec etc. right.  */
-		  rel--;
+		  wrel--, rrel--;
 		  continue;
 		}
 	      else
-		rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+		wrel->r_info = ELF64_R_INFO (r_symndx, r_type);
 	    }
 	  break;
 
@@ -13543,11 +13563,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 			  + R_PPC64_GOT_TPREL16_DS);
 	      else
 		{
-		  rel->r_offset -= d_offset;
-		  bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
+		  wrel->r_offset -= d_offset;
+		  bfd_put_32 (output_bfd, NOP, contents + wrel->r_offset);
 		  r_type = R_PPC64_NONE;
 		}
-	      rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+	      wrel->r_info = ELF64_R_INFO (r_symndx, r_type);
 	    }
 	  break;
 
@@ -13573,17 +13593,17 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 		 reloc is the __tls_get_addr call associated with
 		 the current reloc.  Edit both insns.  */
 	      if (input_section->has_tls_get_addr_call
-		  && rel + 1 < relend
-		  && branch_reloc_hash_match (input_bfd, rel + 1,
+		  && rrel + 1 < relend
+		  && branch_reloc_hash_match (input_bfd, rrel + 1,
 					      htab->tls_get_addr,
 					      htab->tls_get_addr_fd))
-		offset = rel[1].r_offset;
+		offset = rrel[1].r_offset;
 	      /* We read the low GOT_TLS (or TOC16) insn because we
 		 need to keep the destination reg.  It may be
 		 something other than the usual r3, and moved to r3
 		 before the call by intervening code.  */
 	      insn1 = bfd_get_32 (output_bfd,
-				  contents + rel->r_offset - d_offset);
+				  contents + wrel->r_offset - d_offset);
 	      if ((tls_mask & tls_gd) != 0)
 		{
 		  /* IE */
@@ -13591,13 +13611,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 		  insn1 |= 58 << 26;	/* ld */
 		  insn2 = 0x7c636a14;	/* add 3,3,13 */
 		  if (offset != (bfd_vma) -1)
-		    rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
+		    rrel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
 		  if ((tls_mask & TLS_EXPLICIT) == 0)
 		    r_type = (((r_type - (R_PPC64_GOT_TLSGD16 & 3)) & 3)
 			      + R_PPC64_GOT_TPREL16_DS);
 		  else
 		    r_type += R_PPC64_TOC16_DS - R_PPC64_TOC16;
-		  rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+		  wrel->r_info = ELF64_R_INFO (r_symndx, r_type);
 		}
 	      else
 		{
@@ -13617,29 +13637,32 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 			  break;
 		      if (r_symndx >= symtab_hdr->sh_info)
 			r_symndx = STN_UNDEF;
-		      rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
+		      rrel->r_info = ELF64_R_INFO (r_symndx, r_type);
+		      rrel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
 		      if (r_symndx != STN_UNDEF)
-			rel->r_addend -= (local_syms[r_symndx].st_value
-					  + sec->output_offset
-					  + sec->output_section->vma);
+			rrel->r_addend -= (local_syms[r_symndx].st_value
+					   + sec->output_offset
+					   + sec->output_section->vma);
 		    }
 		  else if (toc_symndx != 0)
 		    {
 		      r_symndx = toc_symndx;
-		      rel->r_addend = toc_addend;
+		      rrel->r_info = ELF64_R_INFO (r_symndx, r_type);
+		      rrel->r_addend = toc_addend;
 		    }
 		  r_type = R_PPC64_TPREL16_HA;
-		  rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+		  rrel->r_info = ELF64_R_INFO (r_symndx, r_type);
+		  wrel->r_info = rrel->r_info;
 		  if (offset != (bfd_vma) -1)
 		    {
-		      rel[1].r_info = ELF64_R_INFO (r_symndx,
-						    R_PPC64_TPREL16_LO);
-		      rel[1].r_offset = offset + d_offset;
-		      rel[1].r_addend = rel->r_addend;
+		      rrel[1].r_info = ELF64_R_INFO (r_symndx,
+						     R_PPC64_TPREL16_LO);
+		      rrel[1].r_offset = offset + d_offset;
+		      rrel[1].r_addend = rrel->r_addend;
 		    }
 		}
 	      bfd_put_32 (output_bfd, insn1,
-			  contents + rel->r_offset - d_offset);
+			  contents + wrel->r_offset - d_offset);
 	      if (offset != (bfd_vma) -1)
 		{
 		  insn3 = bfd_get_32 (output_bfd,
@@ -13647,7 +13670,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 		  if (insn3 == NOP
 		      || insn3 == CROR_151515 || insn3 == CROR_313131)
 		    {
-		      rel[1].r_offset += 4;
+		      rrel[1].r_offset += 4;
 		      bfd_put_32 (output_bfd, insn2, contents + offset + 4);
 		      insn2 = NOP;
 		    }
@@ -13658,7 +13681,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 		{
 		  /* We changed the symbol.  Start over in order
 		     to get h, sym, sec etc. right.  */
-		  rel--;
+		  wrel--, rrel--;
 		  continue;
 		}
 	    }
@@ -13668,7 +13691,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	  if (tls_mask != 0 && (tls_mask & TLS_GD) == 0)
 	    {
 	      unsigned int insn2, insn3;
-	      bfd_vma offset = rel->r_offset;
+	      bfd_vma offset = wrel->r_offset;
 
 	      if ((tls_mask & TLS_TPRELGD) != 0)
 		{
@@ -13682,29 +13705,31 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 		  if (toc_symndx != 0)
 		    {
 		      r_symndx = toc_symndx;
-		      rel->r_addend = toc_addend;
+		      rrel->r_addend = toc_addend;
 		    }
 		  r_type = R_PPC64_TPREL16_LO;
-		  rel->r_offset = offset + d_offset;
+		  wrel->r_offset = offset + d_offset;
 		  insn2 = 0x38630000;	/* addi 3,3,0 */
 		}
-	      rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+	      wrel->r_info = ELF64_R_INFO (r_symndx, r_type);
 	      /* Zap the reloc on the _tls_get_addr call too.  */
-	      BFD_ASSERT (offset == rel[1].r_offset);
-	      rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
+	      BFD_ASSERT (offset == rrel[1].r_offset);
+	      rrel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
 	      insn3 = bfd_get_32 (output_bfd,
 				  contents + offset + 4);
 	      if (insn3 == NOP
 		  || insn3 == CROR_151515 || insn3 == CROR_313131)
 		{
-		  rel->r_offset += 4;
+		  wrel->r_offset += 4;
 		  bfd_put_32 (output_bfd, insn2, contents + offset + 4);
 		  insn2 = NOP;
 		}
 	      bfd_put_32 (output_bfd, insn2, contents + offset);
 	      if ((tls_mask & TLS_TPRELGD) == 0 && toc_symndx != 0)
 		{
-		  rel--;
+		  rrel->r_offset = wrel->r_offset;
+		  rrel->r_info = wrel->r_info;
+		  wrel--, rrel--;
 		  continue;
 		}
 	    }
@@ -13714,7 +13739,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	  if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
 	    {
 	      unsigned int insn2, insn3;
-	      bfd_vma offset = rel->r_offset;
+	      bfd_vma offset = wrel->r_offset;
 
 	      if (toc_symndx)
 		sec = local_sections[toc_symndx];
@@ -13725,59 +13750,59 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 		  break;
 	      if (r_symndx >= symtab_hdr->sh_info)
 		r_symndx = STN_UNDEF;
-	      rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
+	      rrel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
 	      if (r_symndx != STN_UNDEF)
-		rel->r_addend -= (local_syms[r_symndx].st_value
-				  + sec->output_offset
-				  + sec->output_section->vma);
+		rrel->r_addend -= (local_syms[r_symndx].st_value
+				   + sec->output_offset
+				   + sec->output_section->vma);
 
 	      r_type = R_PPC64_TPREL16_LO;
-	      rel->r_info = ELF64_R_INFO (r_symndx, r_type);
-	      rel->r_offset = offset + d_offset;
+	      rrel->r_info = ELF64_R_INFO (r_symndx, r_type);
+	      rrel->r_offset = offset + d_offset;
 	      /* Zap the reloc on the _tls_get_addr call too.  */
-	      BFD_ASSERT (offset == rel[1].r_offset);
-	      rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
+	      BFD_ASSERT (offset == rrel[1].r_offset);
+	      rrel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
 	      insn2 = 0x38630000;	/* addi 3,3,0 */
 	      insn3 = bfd_get_32 (output_bfd,
 				  contents + offset + 4);
 	      if (insn3 == NOP
 		  || insn3 == CROR_151515 || insn3 == CROR_313131)
 		{
-		  rel->r_offset += 4;
+		  rrel->r_offset += 4;
 		  bfd_put_32 (output_bfd, insn2, contents + offset + 4);
 		  insn2 = NOP;
 		}
 	      bfd_put_32 (output_bfd, insn2, contents + offset);
-	      rel--;
+	      wrel--, rrel--;
 	      continue;
 	    }
 	  break;
 
 	case R_PPC64_DTPMOD64:
-	  if (rel + 1 < relend
-	      && rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64)
-	      && rel[1].r_offset == rel->r_offset + 8)
+	  if (rrel + 1 < relend
+	      && rrel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64)
+	      && rrel[1].r_offset == wrel->r_offset + 8)
 	    {
 	      if ((tls_mask & TLS_GD) == 0)
 		{
-		  rel[1].r_info = ELF64_R_INFO (r_symndx, R_PPC64_NONE);
+		  rrel[1].r_info = ELF64_R_INFO (r_symndx, R_PPC64_NONE);
 		  if ((tls_mask & TLS_TPRELGD) != 0)
 		    r_type = R_PPC64_TPREL64;
 		  else
 		    {
-		      bfd_put_64 (output_bfd, 1, contents + rel->r_offset);
+		      bfd_put_64 (output_bfd, 1, contents + wrel->r_offset);
 		      r_type = R_PPC64_NONE;
 		    }
-		  rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+		  wrel->r_info = ELF64_R_INFO (r_symndx, r_type);
 		}
 	    }
 	  else
 	    {
 	      if ((tls_mask & TLS_LD) == 0)
 		{
-		  bfd_put_64 (output_bfd, 1, contents + rel->r_offset);
+		  bfd_put_64 (output_bfd, 1, contents + wrel->r_offset);
 		  r_type = R_PPC64_NONE;
-		  rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+		  wrel->r_info = ELF64_R_INFO (r_symndx, r_type);
 		}
 	    }
 	  break;
@@ -13786,7 +13811,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	  if ((tls_mask & TLS_TPREL) == 0)
 	    {
 	      r_type = R_PPC64_NONE;
-	      rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+	      wrel->r_info = ELF64_R_INFO (r_symndx, r_type);
 	    }
 	  break;
 
@@ -13801,24 +13826,24 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	  if (!bfd_link_pic (info)
 	      && !info->traditional_format
 	      && h != NULL && &h->elf == htab->elf.hgot
-	      && rel + 1 < relend
-	      && rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_REL16_LO)
-	      && rel[1].r_offset == rel->r_offset + 4
-	      && rel[1].r_addend == rel->r_addend + 4
+	      && rrel + 1 < relend
+	      && rrel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_REL16_LO)
+	      && rrel[1].r_offset == wrel->r_offset + 4
+	      && rrel[1].r_addend == wrel->r_addend + 4
 	      && relocation + 0x80008000 <= 0xffffffff)
 	    {
 	      unsigned int insn1, insn2;
-	      bfd_vma offset = rel->r_offset - d_offset;
+	      bfd_vma offset = wrel->r_offset - d_offset;
 	      insn1 = bfd_get_32 (output_bfd, contents + offset);
 	      insn2 = bfd_get_32 (output_bfd, contents + offset + 4);
 	      if ((insn1 & 0xffff0000) == 0x3c4c0000 /* addis 2,12 */
 		  && (insn2 & 0xffff0000) == 0x38420000 /* addi 2,2 */)
 		{
 		  r_type = R_PPC64_ADDR16_HA;
-		  rel->r_info = ELF64_R_INFO (r_symndx, r_type);
-		  rel->r_addend -= d_offset;
-		  rel[1].r_info = ELF64_R_INFO (r_symndx, R_PPC64_ADDR16_LO);
-		  rel[1].r_addend -= d_offset + 4;
+		  wrel->r_info = ELF64_R_INFO (r_symndx, r_type);
+		  wrel->r_addend -= d_offset;
+		  rrel[1].r_info = ELF64_R_INFO (r_symndx, R_PPC64_ADDR16_LO);
+		  rrel[1].r_addend -= d_offset + 4;
 		  bfd_put_32 (output_bfd, 0x3c400000, contents + offset);
 		}
 	    }
@@ -13828,7 +13853,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       /* Handle other relocations that tweak non-addend part of insn.  */
       insn = 0;
       max_br_offset = 1 << 25;
-      addend = rel->r_addend;
+      addend = wrel->r_addend;
       reloc_dest = DEST_NORMAL;
       switch (r_type)
 	{
@@ -13836,18 +13861,18 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	  break;
 
 	case R_PPC64_TOCSAVE:
-	  if (relocation + addend == (rel->r_offset
+	  if (relocation + addend == (wrel->r_offset
 				      + input_section->output_offset
 				      + input_section->output_section->vma)
 	      && tocsave_find (htab, NO_INSERT,
-			       &local_syms, rel, input_bfd))
+			       &local_syms, wrel, input_bfd))
 	    {
-	      insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+	      insn = bfd_get_32 (input_bfd, contents + wrel->r_offset);
 	      if (insn == NOP
 		  || insn == CROR_151515 || insn == CROR_313131)
 		bfd_put_32 (input_bfd,
 			    STD_R2_0R1 + STK_TOC (htab),
-			    contents + rel->r_offset);
+			    contents + wrel->r_offset);
 	    }
 	  break;
 
@@ -13861,7 +13886,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	case R_PPC64_ADDR14_BRNTAKEN:
 	case R_PPC64_REL14_BRNTAKEN:
 	  insn |= bfd_get_32 (output_bfd,
-			      contents + rel->r_offset) & ~(0x01 << 21);
+			      contents + wrel->r_offset) & ~(0x01 << 21);
 	  /* Fall thru.  */
 
 	case R_PPC64_REL14:
@@ -13893,18 +13918,18 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	      /* All of these stubs will modify r2, so there must be a
 		 branch and link followed by a nop.  The nop is
 		 replaced by an insn to restore r2.  */
-	      if (rel->r_offset + 8 <= input_section->size)
+	      if (wrel->r_offset + 8 <= input_section->size)
 		{
 		  unsigned long br;
 
 		  br = bfd_get_32 (input_bfd,
-				   contents + rel->r_offset);
+				   contents + wrel->r_offset);
 		  if ((br & 1) != 0)
 		    {
 		      unsigned long nop;
 
 		      nop = bfd_get_32 (input_bfd,
-					contents + rel->r_offset + 4);
+					contents + wrel->r_offset + 4);
 		      if (nop == NOP
 			  || nop == CROR_151515 || nop == CROR_313131)
 			{
@@ -13918,7 +13943,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 			  else
 			    bfd_put_32 (input_bfd,
 					LD_R2_0R1 + STK_TOC (htab),
-					contents + rel->r_offset + 4);
+					contents + wrel->r_offset + 4);
 			  can_plt_call = TRUE;
 			}
 		    }
@@ -13972,12 +13997,12 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 		    info->callbacks->einfo
 		      (_("%P: %H: call to `%T' lacks nop, can't restore toc; "
 			 "recompile with -fPIC\n"),
-		       input_bfd, input_section, rel->r_offset, sym_name);
+		       input_bfd, input_section, wrel->r_offset, sym_name);
 		  else
 		    info->callbacks->einfo
 		      (_("%P: %H: call to `%T' lacks nop, can't restore toc; "
 			 "(-mcmodel=small toc adjust stub)\n"),
-		       input_bfd, input_section, rel->r_offset, sym_name);
+		       input_bfd, input_section, wrel->r_offset, sym_name);
 
 		  bfd_set_error (bfd_error_bad_value);
 		  ret = FALSE;
@@ -14009,7 +14034,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
 	  /* If the branch is out of reach we ought to have a long
 	     branch stub.  */
-	  from = (rel->r_offset
+	  from = (wrel->r_offset
 		  + input_section->output_offset
 		  + input_section->output_section->vma);
 
@@ -14050,9 +14075,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 		   || stub_entry->stub_type == ppc_stub_plt_call_r2save)
 		  && (ALWAYS_EMIT_R2SAVE
 		      || stub_entry->stub_type == ppc_stub_plt_call_r2save)
-		  && rel + 1 < relend
-		  && rel[1].r_offset == rel->r_offset + 4
-		  && ELF64_R_TYPE (rel[1].r_info) == R_PPC64_TOCSAVE)
+		  && rrel + 1 < relend
+		  && rrel[1].r_offset == wrel->r_offset + 4
+		  && ELF64_R_TYPE (rrel[1].r_info) == R_PPC64_TOCSAVE)
 		relocation += 4;
 	    }
 
@@ -14077,7 +14102,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 		    insn ^= 0x01 << 21;
 		}
 
-	      bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
+	      bfd_put_32 (output_bfd, insn, contents + wrel->r_offset);
 	    }
 
 	  /* NOP out calls to undefined weak functions.
@@ -14090,7 +14115,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 		   && relocation == 0
 		   && addend == 0)
 	    {
-	      bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
+	      bfd_put_32 (output_bfd, NOP, contents + wrel->r_offset);
 	      continue;
 	    }
 	  break;
@@ -14445,7 +14470,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 		 resolve to zero.  This is really just a tweak, since
 		 code using weak externs ought to check that they are
 		 defined before using them.  */
-	      bfd_byte *p = contents + rel->r_offset - d_offset;
+	      bfd_byte *p = contents + wrel->r_offset - d_offset;
 
 	      insn = bfd_get_32 (output_bfd, p);
 	      insn = _bfd_elf_ppc_at_tprel_transform (insn, 13);
@@ -14561,7 +14586,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	      relocate = FALSE;
 
 	      out_off = _bfd_elf_section_offset (output_bfd, info,
-						 input_section, rel->r_offset);
+						 input_section, wrel->r_offset);
 	      if (out_off == (bfd_vma) -1)
 		skip = TRUE;
 	      else if (out_off == (bfd_vma) -2)
@@ -14569,7 +14594,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	      out_off += (input_section->output_section->vma
 			  + input_section->output_offset);
 	      outrel.r_offset = out_off;
-	      outrel.r_addend = rel->r_addend;
+	      outrel.r_addend = wrel->r_addend;
 
 	      /* Optimize unaligned reloc use.  */
 	      if ((r_type == R_PPC64_ADDR64 && (out_off & 7) != 0)
@@ -14641,7 +14666,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 			  info->callbacks->einfo
 			    (_("%P: %H: %s for indirect "
 			       "function `%T' unsupported\n"),
-			     input_bfd, input_section, rel->r_offset,
+			     input_bfd, input_section, wrel->r_offset,
 			     ppc64_elf_howto_table[r_type]->name,
 			     sym_name);
 			  ret = FALSE;
@@ -14721,7 +14746,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 		  else if (ppc64_elf_howto_table[r_type]->pc_relative)
 		    addend = (input_section->output_section->vma
 			      + input_section->output_offset
-			      + rel->r_offset);
+			      + wrel->r_offset);
 		}
 	    }
 	  break;
@@ -14787,7 +14812,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	  if (htab->do_toc_opt && relocation + addend + 0x8000 < 0x10000
 	      && !ppc64_elf_tdata (input_bfd)->unexpected_toc_insn)
 	    {
-	      bfd_byte *p = contents + (rel->r_offset & ~3);
+	      bfd_byte *p = contents + (wrel->r_offset & ~3);
 	      bfd_put_32 (input_bfd, NOP, p);
 	    }
 	  break;
@@ -14803,7 +14828,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	  if (htab->do_toc_opt && relocation + addend + 0x8000 < 0x10000
 	      && !ppc64_elf_tdata (input_bfd)->unexpected_toc_insn)
 	    {
-	      bfd_byte *p = contents + (rel->r_offset & ~3);
+	      bfd_byte *p = contents + (wrel->r_offset & ~3);
 	      insn = bfd_get_32 (input_bfd, p);
 	      if ((insn & (0x3f << 26)) == 12u << 26 /* addic */)
 		{
@@ -14882,7 +14907,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	case R_PPC64_TPREL16_LO_DS:
 	case R_PPC64_DTPREL16_DS:
 	case R_PPC64_DTPREL16_LO_DS:
-	  insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
+	  insn = bfd_get_32 (input_bfd, contents + (wrel->r_offset & ~3));
 	  mask = 3;
 	  /* If this reloc is against an lq insn, then the value must be
 	     a multiple of 16.  This is somewhat of a hack, but the
@@ -14896,7 +14921,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	    {
 	      info->callbacks->einfo
 		(_("%P: %H: error: %s not a multiple of %u\n"),
-		 input_bfd, input_section, rel->r_offset,
+		 input_bfd, input_section, wrel->r_offset,
 		 howto->name,
 		 mask + 1);
 	      bfd_set_error (bfd_error_bad_value);
@@ -14913,11 +14938,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	  && !((input_section->flags & SEC_DEBUGGING) != 0
 	       && h->elf.def_dynamic)
 	  && _bfd_elf_section_offset (output_bfd, info, input_section,
-				      rel->r_offset) != (bfd_vma) -1)
+				      wrel->r_offset) != (bfd_vma) -1)
 	{
 	  info->callbacks->einfo
 	    (_("%P: %H: unresolvable %s against `%T'\n"),
-	     input_bfd, input_section, rel->r_offset,
+	     input_bfd, input_section, wrel->r_offset,
 	     howto->name,
 	     h->elf.root.root.string);
 	  ret = FALSE;
@@ -14932,7 +14957,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	{
 	  enum complain_overflow complain = complain_overflow_signed;
 
-	  insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
+	  insn = bfd_get_32 (input_bfd, contents + (wrel->r_offset & ~3));
 	  if ((insn & (0x3f << 26)) == 10u << 26 /* cmpli */)
 	    complain = complain_overflow_bitfield;
 	  else if (howto->rightshift == 0
@@ -14952,7 +14977,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	}
 
       r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
-				    rel->r_offset, relocation, addend);
+				    wrel->r_offset, relocation, addend);
 
       if (r != bfd_reloc_ok)
 	{
@@ -14985,7 +15010,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 		  if (!((*info->callbacks->reloc_overflow)
 			(info, &h->elf.root, sym_name,
 			 reloc_name, orig_rel.r_addend,
-			 input_bfd, input_section, rel->r_offset)))
+			 input_bfd, input_section, wrel->r_offset)))
 		    return FALSE;
 		}
 	    }
@@ -14993,7 +15018,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	    {
 	      info->callbacks->einfo
 		(_("%P: %H: %s against `%T': error %d\n"),
-		 input_bfd, input_section, rel->r_offset,
+		 input_bfd, input_section, wrel->r_offset,
 		 reloc_name, sym_name, (int) r);
 	      ret = FALSE;
 	    }
@@ -15002,6 +15027,26 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	}
     }
 
+  if (wrel != rrel)
+    {
+      Elf_Internal_Shdr *rel_hdr;
+      size_t deleted = rrel - wrel;
+
+      rel_hdr = _bfd_elf_single_rel_hdr (input_section->output_section);
+      rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted;
+      if (rel_hdr->sh_size == 0)
+	{
+	  /* It is too late to remove an empty reloc section.  Leave
+	     one NONE reloc.
+	     ??? What is wrong with an empty section???  */
+	  rel_hdr->sh_size = rel_hdr->sh_entsize;
+	  deleted -= 1;
+	}
+      rel_hdr = _bfd_elf_single_rel_hdr (input_section);
+      rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted;
+      input_section->reloc_count -= deleted;
+    }
+
   /* If we're emitting relocations, then shortly after this function
      returns, reloc offsets and addends for this section will be
      adjusted.  Worse, reloc symbol indices will be for the output
@@ -15011,12 +15056,12 @@ ppc64_elf_relocate_section (bfd *output_bfd,
     {
       bfd_size_type amt;
       amt = input_section->reloc_count * sizeof (Elf_Internal_Rela);
-      rel = bfd_alloc (input_bfd, amt);
+      wrel = bfd_alloc (input_bfd, amt);
       BFD_ASSERT (ppc64_elf_tdata (input_bfd)->opd.relocs == NULL);
-      ppc64_elf_tdata (input_bfd)->opd.relocs = rel;
-      if (rel == NULL)
+      ppc64_elf_tdata (input_bfd)->opd.relocs = wrel;
+      if (wrel == NULL)
 	return FALSE;
-      memcpy (rel, relocs, amt);
+      memcpy (wrel, relocs, amt);
     }
   return ret;
 }

-- 
Alan Modra
Australia Development Lab, IBM



More information about the Binutils mailing list