powerpc relax_section and section contents cache
authorAlan Modra <amodra@gmail.com>
Sat, 8 Feb 2014 01:56:53 +0000 (12:26 +1030)
committerAlan Modra <amodra@gmail.com>
Sun, 9 Feb 2014 12:55:14 +0000 (23:25 +1030)
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.

bfd/ChangeLog
bfd/elf-bfd.h
bfd/elf32-ppc.c
bfd/elflink.c
bfd/elfxx-target.h

index 37074c9071d7753198cac91e41e7b8f5211a8a29..5b828a3b2b1cf72d250e5ca9b15ed019844c6917 100644 (file)
@@ -1,3 +1,17 @@
+2014-02-09  Alan Modra  <amodra@gmail.com>
+
+       * 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.
+
 2014-02-07  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
 
        * cache.c (bfd_cache_max_open): Cast RLIM_INFINITY to rlim_t.
index 0aab5fa065a6b64a0f25b650c1e753a89e1c3b7c..76cac2febea3ba66e04a60b3f39143f55e07235b 100644 (file)
@@ -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
index d13d31b4ece23ad701e32b41dca4d329f54d8b0a..0b43b9b9a87a42b3399a0975f75c921c75ae2e3e 100644 (file)
@@ -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;
@@ -7096,54 +7088,6 @@ ppc_elf_relax_section (bfd *abfd,
       newsize = trampoff + relax_info->workaround_size;
     }
 
-  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;
 
@@ -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
index 88967c835fa7dc7d164e70ade4093c6c079a7bb1..af4f6bb190d0bf275559ed59dc4aa7f0efb8ef9d 100644 (file)
@@ -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;
index 2e7cbca3489f8b915b87975a0feb4a9fbe0db794..74e1b32b2da432ae7c7a428d7aa4abfec6d74695 100644 (file)
 #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.  */