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]

powerpc relax_section and section contents cache


This patch provides a means for backend relax_section support to
increase the size of a section without needing to reallocate
section contents.  This helps reduce memory usage when the added space
does not need to be written in relax_section, as is the case for
powerpc.  Writing the stubs later means a few tweaks are needed in the
powerpc relocate_section function, but also removes some code
duplication since the extra ld -r relocs can be written there too.

	* elf-bfd.h (struct elf_backend_data): Add caches_rawsize.
	* elfxx-target.h (elf_backend_caches_rawsize): Define.
	(elfNN_bed): Init new field.
	* elflink.c (elf_link_input_bfd): Handle caches_rawsize.
	* elf32-ppc.c (shared_stub_entry): Zero addi offset.
	(ppc_elf_relax_section): Don't reallocate section here, write
	stubs, or write out relocs for ld -r here..
	(ppc_elf_relocate_section): ..instead write stubs here, and use
	existing code to write out relocs for ld -r.  Fix offset
	adjustment on reloc for little-endian.
	(elf_backend_caches_rawsize): Define.

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 0aab5fa..76cac2f 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1342,6 +1342,11 @@ struct elf_backend_data
      other file in the link needs to have a .note.GNU-stack section
      for a PT_GNU_STACK segment to be created.  */
   unsigned default_execstack : 1;
+
+  /* True if elf_section_data(sec)->this_hdr.contents is sec->rawsize
+     in length rather than sec->size in length, if sec->rawsize is
+     non-zero and smaller than sec->size.  */
+  unsigned caches_rawsize : 1;
 };
 
 /* Information about reloc sections associated with a bfd_elf_section_data
diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
index 2e7cbca..74e1b32 100644
--- a/bfd/elfxx-target.h
+++ b/bfd/elfxx-target.h
@@ -109,6 +109,9 @@
 #ifndef elf_backend_default_execstack
 #define elf_backend_default_execstack 1
 #endif
+#ifndef elf_backend_caches_rawsize
+#define elf_backend_caches_rawsize 0
+#endif
 #ifndef elf_backend_stack_align
 #define elf_backend_stack_align 16
 #endif
@@ -794,7 +797,8 @@ static struct elf_backend_data elfNN_bed =
   elf_backend_want_got_sym,
   elf_backend_want_dynbss,
   elf_backend_want_p_paddr_set_to_zero,
-  elf_backend_default_execstack
+  elf_backend_default_execstack,
+  elf_backend_caches_rawsize
 };
 
 /* Forward declaration for use when initialising alternative_target field.  */
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 88967c8..af4f6bb 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -9549,7 +9549,16 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
 	 file, so the contents field will not have been set by any of
 	 the routines which work on output files.  */
       if (elf_section_data (o)->this_hdr.contents != NULL)
-	contents = elf_section_data (o)->this_hdr.contents;
+	{
+	  contents = elf_section_data (o)->this_hdr.contents;
+	  if (bed->caches_rawsize
+	      && o->rawsize != 0
+	      && o->rawsize < o->size)
+	    {
+	      memcpy (flinfo->contents, contents, o->rawsize);
+	      contents = flinfo->contents;
+	    }
+	}
       else
 	{
 	  contents = flinfo->contents;
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index d13d31b..0b43b9b 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -6623,7 +6623,7 @@ static const int shared_stub_entry[] =
     0x429f0005, /* bcl 20, 31, .Lxxx */
     0x7d8802a6, /* mflr 12 */
     0x3d8c0000, /* addis 12, 12, (xxx-.Lxxx)@ha */
-    0x398c0008, /* addi 12, 12, (xxx-.Lxxx)@l */
+    0x398c0000, /* addi 12, 12, (xxx-.Lxxx)@l */
     0x7c0803a6, /* mtlr 0 */
     0x7d8903a6, /* mtctr 12 */
     0x4e800420, /* bctr */
@@ -6645,10 +6645,7 @@ struct ppc_elf_relax_info
 /* This function implements long branch trampolines, and the ppc476
    icache bug workaround.  Any section needing trampolines or patch
    space for the workaround has its size extended so that we can
-   add trampolines at the end of the section.  FIXME: We write out
-   trampoline templates here and later modify them in
-   relocate_section.  We'd save a realloc if we left writing the
-   templates to relocate_section.  */
+   add trampolines at the end of the section.  */
 
 static bfd_boolean
 ppc_elf_relax_section (bfd *abfd,
@@ -6704,12 +6701,14 @@ ppc_elf_relax_section (bfd *abfd,
     isec->rawsize = isec->size;
   trampbase = isec->size;
 
+  BFD_ASSERT (isec->sec_info_type == SEC_INFO_TYPE_NONE
+	      || isec->sec_info_type == SEC_INFO_TYPE_TARGET);
+  isec->sec_info_type = SEC_INFO_TYPE_TARGET;
+
   if (htab->params->ppc476_workaround)
     {
       if (elf_section_data (isec)->sec_info == NULL)
 	{
-	  BFD_ASSERT (isec->sec_info_type == SEC_INFO_TYPE_NONE);
-	  isec->sec_info_type = SEC_INFO_TYPE_TARGET;
 	  elf_section_data (isec)->sec_info
 	    = bfd_zalloc (abfd, sizeof (struct ppc_elf_relax_info));
 	  if (elf_section_data (isec)->sec_info == NULL)
@@ -7082,13 +7081,6 @@ ppc_elf_relax_section (bfd *abfd,
 	    {
 	      relax_info->workaround_size = newsize;
 	      workaround_change = TRUE;
-	      if (contents == NULL)
-		{
-		  if (elf_section_data (isec)->this_hdr.contents != NULL)
-		    contents = elf_section_data (isec)->this_hdr.contents;
-		  else if (!bfd_malloc_and_get_section (abfd, isec, &contents))
-		    goto error_return;
-		}
 	    }
 	  /* Ensure relocate_section is called.  */
 	  isec->flags |= SEC_RELOC;
@@ -7097,54 +7089,6 @@ ppc_elf_relax_section (bfd *abfd,
     }
 
   if (changes || workaround_change)
-    {
-      contents = bfd_realloc_or_free (contents, newsize);
-      if (contents == NULL)
-	goto error_return;
-
-      /* Branch around the trampolines.  */
-      if (maybe_pasted)
-	{
-	  bfd_vma val = B + newsize - isec->rawsize;
-	  bfd_put_32 (abfd, val, contents + isec->rawsize);
-	}
-    }
-
-  /* Write out the trampolines.  */
-  if (changes)
-    {
-      const int *stub;
-      bfd_byte *dest;
-      int i, size;
-
-      dest = contents + trampbase;
-      if (maybe_pasted && trampbase == isec->rawsize)
-	dest += 4;
-
-      if (link_info->shared)
-	{
-	  stub = shared_stub_entry;
-	  size = ARRAY_SIZE (shared_stub_entry);
-	}
-      else
-	{
-	  stub = stub_entry;
-	  size = ARRAY_SIZE (stub_entry);
-	}
-
-      i = 0;
-      while (dest < contents + trampoff)
-	{
-	  bfd_put_32 (abfd, stub[i], dest);
-	  i++;
-	  if (i == size)
-	    i = 0;
-	  dest += 4;
-	}
-      BFD_ASSERT (i == 0);
-    }
-
-  if (changes || workaround_change)
     isec->size = newsize;
 
   if (isymbuf != NULL
@@ -7162,7 +7106,7 @@ ppc_elf_relax_section (bfd *abfd,
   if (contents != NULL
       && elf_section_data (isec)->this_hdr.contents != contents)
     {
-      if (!changes && !workaround_change && !link_info->keep_memory)
+      if (!changes && !link_info->keep_memory)
 	free (contents);
       else
 	{
@@ -7202,27 +7146,6 @@ ppc_elf_relax_section (bfd *abfd,
     free (internal_relocs);
 
   *again = changes != 0 || workaround_change;
-  if (!*again && link_info->relocatable && htab->params->branch_trampolines)
-    {
-      /* Convert the internal relax relocs to external form.  */
-      for (irel = internal_relocs; irel < irelend; irel++)
-	if (ELF32_R_TYPE (irel->r_info) == R_PPC_RELAX)
-	  {
-	    unsigned long r_symndx = ELF32_R_SYM (irel->r_info);
-
-	    /* Rewrite the reloc and convert one of the trailing nop
-	       relocs to describe this relocation.  */
-	    BFD_ASSERT (ELF32_R_TYPE (irelend[-1].r_info) == R_PPC_NONE);
-	    /* The relocs are at the bottom 2 bytes */
-	    irel[0].r_offset += 2;
-	    memmove (irel + 1, irel, (irelend - irel - 1) * sizeof (*irel));
-	    irel[0].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA);
-	    irel[1].r_offset += 4;
-	    irel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO);
-	    irel++;
-	  }
-    }
-
   return TRUE;
 
  error_return:
@@ -7639,7 +7562,10 @@ ppc_elf_relocate_section (bfd *output_bfd,
 		 addend specifies the GOT pointer offset within .got2.  */
 	      rel->r_addend += got2->output_offset;
 	    }
-	  continue;
+	  if (r_type != R_PPC_RELAX_PLT
+	      && r_type != R_PPC_RELAX_PLTREL24
+	      && r_type != R_PPC_RELAX)
+	    continue;
 	}
 
       /* TLS optimizations.  Replace instruction sequences and relocs
@@ -8554,36 +8480,59 @@ ppc_elf_relocate_section (bfd *output_bfd,
 	  /* Fall thru */
 
 	case R_PPC_RELAX:
-	  if (info->shared)
-	    relocation -= (input_section->output_section->vma
-			   + input_section->output_offset
-			   + rel->r_offset - 4);
-
 	  {
-	    unsigned long t0;
-	    unsigned long t1;
+	    const int *stub;
+	    size_t size;
+	    size_t insn_offset = rel->r_offset;
+	    unsigned int insn;
 
-	    t0 = bfd_get_32 (output_bfd, contents + rel->r_offset);
-	    t1 = bfd_get_32 (output_bfd, contents + rel->r_offset + 4);
-
-	    /* We're clearing the bits for R_PPC_ADDR16_HA
-	       and R_PPC_ADDR16_LO here.  */
-	    t0 &= ~0xffff;
-	    t1 &= ~0xffff;
+	    if (info->shared)
+	      {
+		relocation -= (input_section->output_section->vma
+			       + input_section->output_offset
+			       + rel->r_offset - 4);
+		stub = shared_stub_entry;
+		bfd_put_32 (output_bfd, stub[0], contents + insn_offset - 12);
+		bfd_put_32 (output_bfd, stub[1], contents + insn_offset - 8);
+		bfd_put_32 (output_bfd, stub[2], contents + insn_offset - 4);
+		stub += 3;
+		size = ARRAY_SIZE (shared_stub_entry) - 3;
+	      }
+	    else
+	      {
+		stub = stub_entry;
+		size = ARRAY_SIZE (stub_entry);
+	      }
 
-	    /* t0 is HA, t1 is LO */
 	    relocation += addend;
-	    t0 |= ((relocation + 0x8000) >> 16) & 0xffff;
-	    t1 |= relocation & 0xffff;
-
-	    bfd_put_32 (output_bfd, t0, contents + rel->r_offset);
-	    bfd_put_32 (output_bfd, t1, contents + rel->r_offset + 4);
+	    if (info->relocatable)
+	      relocation = 0;
+
+	    /* First insn is HA, second is LO.  */
+	    insn = *stub++;
+	    insn |= ((relocation + 0x8000) >> 16) & 0xffff;
+	    bfd_put_32 (output_bfd, insn, contents + insn_offset);
+	    insn_offset += 4;
+
+	    insn = *stub++;
+	    insn |= relocation & 0xffff;
+	    bfd_put_32 (output_bfd, insn, contents + insn_offset);
+	    insn_offset += 4;
+	    size -= 2;
+
+	    while (size != 0)
+	      {
+		insn = *stub++;
+		--size;
+		bfd_put_32 (output_bfd, insn, contents + insn_offset);
+		insn_offset += 4;
+	      }
 
 	    /* Rewrite the reloc and convert one of the trailing nop
 	       relocs to describe this relocation.  */
 	    BFD_ASSERT (ELF32_R_TYPE (relend[-1].r_info) == R_PPC_NONE);
 	    /* The relocs are at the bottom 2 bytes */
-	    rel[0].r_offset += 2;
+	    rel[0].r_offset += d_offset;
 	    memmove (rel + 1, rel, (relend - rel - 1) * sizeof (*rel));
 	    rel[0].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA);
 	    rel[1].r_offset += 4;
@@ -9174,6 +9123,16 @@ ppc_elf_relocate_section (bfd *output_bfd,
   fprintf (stderr, "\n");
 #endif
 
+  if (input_section->sec_info_type == SEC_INFO_TYPE_TARGET
+      && input_section->size != input_section->rawsize
+      && (strcmp (input_section->output_section->name, ".init") == 0
+	  || strcmp (input_section->output_section->name, ".fini") == 0))
+    {
+      /* Branch around the trampolines.  */
+      unsigned int insn = B + input_section->size - input_section->rawsize;
+      bfd_put_32 (input_bfd, insn, contents + input_section->rawsize);
+    }
+
   if (htab->params->ppc476_workaround
       && input_section->sec_info_type == SEC_INFO_TYPE_TARGET)
     {
@@ -10137,6 +10096,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 #define elf_backend_can_gc_sections	1
 #define elf_backend_can_refcount	1
 #define elf_backend_rela_normal		1
+#define elf_backend_caches_rawsize	1
 
 #define bfd_elf32_mkobject			ppc_elf_mkobject
 #define bfd_elf32_bfd_merge_private_bfd_data	ppc_elf_merge_private_bfd_data

-- 
Alan Modra
Australia Development Lab, IBM


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