bfd/
authorTrevor Smigiel <Trevor_Smigiel@playstation.sony.com>
Wed, 5 Aug 2009 20:40:34 +0000 (20:40 +0000)
committerTrevor Smigiel <Trevor_Smigiel@playstation.sony.com>
Wed, 5 Aug 2009 20:40:34 +0000 (20:40 +0000)
* elf32-spu.h (spu_elf_params): Add member emit_fixups.
(spu_elf_size_sections): Declare prototype.
* elf32-spu.c (spu_link_hash_table): Add member sfixup.
(FIXUP_RECORD_SIZE, FIXUP_GET, FIXUP_PUT): New macros.
(spu_elf_emit_fixup): New function.
(spu_elf_relocate_section): Emit fixup for each SPU_ADDR32.
(spu_elf_size_sections): New function.
ld/
* emulparams/elf32_spu.sh (OTHER_READONLY_SECTIONS): Add .fixup
section and __fixup_start symbol.
* emultempl/spuelf.em (params): Initialize emit_fixups member.
(spu_before_allocation): Call spu_elf_size_sections.
(OPTION_SPU_EMIT_FIXUPS): Define.
(PARSE_AND_LIST_LONGOPTS): Add --emit-fixups.
(PARSE_AND_LIST_ARGS_CASES): Handle --emit-fixups.
* ld.texinfo (--emit-fixups): Document.
ld/testsuite/
* ld-spu/fixup.d: New.
* ld-spu/fixup.s: New.

bfd/ChangeLog
bfd/elf32-spu.c
bfd/elf32-spu.h
ld/ChangeLog
ld/emulparams/elf32_spu.sh
ld/emultempl/spuelf.em
ld/testsuite/ChangeLog
ld/testsuite/ld-spu/fixup.d [new file with mode: 0644]
ld/testsuite/ld-spu/fixup.s [new file with mode: 0644]

index 577918c..a18c0db 100644 (file)
@@ -1,3 +1,13 @@
+2009-08-05  Trevor Smigiel  <Trevor_Smigiel@playstation.sony.com>
+
+       * elf32-spu.h (spu_elf_params): Add member emit_fixups.
+       (spu_elf_size_sections): Declare prototype.
+       * elf32-spu.c (spu_link_hash_table): Add member sfixup.
+       (FIXUP_RECORD_SIZE, FIXUP_GET, FIXUP_PUT): New macros.
+       (spu_elf_emit_fixup): New function.
+       (spu_elf_relocate_section): Emit fixup for each SPU_ADDR32.
+       (spu_elf_size_sections): New function.
+
 2009-08-05  Nathan Sidwell  <nathan@codesourcery.com>
 
        * elf32-arm.c (elf32_arm_stub_type): Add arm_stub_a8_veneer_lwm.
index b5c90a1..16f9450 100644 (file)
@@ -344,6 +344,9 @@ struct spu_link_hash_table
   /* Count of overlay stubs needed in non-overlay area.  */
   unsigned int non_ovly_stub;
 
+  /* Pointer to the fixup section */
+  asection *sfixup;
+
   /* Set on error.  */
   unsigned int stub_err : 1;
 };
@@ -558,6 +561,7 @@ get_sym_h (struct elf_link_hash_entry **hp,
 bfd_boolean
 spu_elf_create_sections (struct bfd_link_info *info)
 {
+  struct spu_link_hash_table *htab = spu_hash_table (info);
   bfd *ibfd;
 
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
@@ -600,6 +604,19 @@ spu_elf_create_sections (struct bfd_link_info *info)
       s->contents = data;
     }
 
+  if (htab->params->emit_fixups)
+    {
+      asection *s;
+      flagword flags;
+      ibfd = info->input_bfds;
+      flags = SEC_LOAD | SEC_ALLOC | SEC_READONLY | SEC_HAS_CONTENTS
+             | SEC_IN_MEMORY;
+      s = bfd_make_section_anyway_with_flags (ibfd, ".fixup", flags);
+      if (s == NULL || !bfd_set_section_alignment (ibfd, s, 2))
+       return FALSE;
+      htab->sfixup = s;
+    }
+
   return TRUE;
 }
 
@@ -4718,6 +4735,48 @@ spu_elf_count_relocs (struct bfd_link_info *info, asection *sec)
   return count;
 }
 
+/* Functions for adding fixup records to .fixup */
+
+#define FIXUP_RECORD_SIZE 4
+
+#define FIXUP_PUT(output_bfd,htab,index,addr) \
+         bfd_put_32 (output_bfd, addr, \
+                     htab->sfixup->contents + FIXUP_RECORD_SIZE * (index))
+#define FIXUP_GET(output_bfd,htab,index) \
+         bfd_get_32 (output_bfd, \
+                     htab->sfixup->contents + FIXUP_RECORD_SIZE * (index))
+
+/* Store OFFSET in .fixup.  This assumes it will be called with an
+   increasing OFFSET.  When this OFFSET fits with the last base offset,
+   it just sets a bit, otherwise it adds a new fixup record.  */
+static void
+spu_elf_emit_fixup (bfd * output_bfd, struct bfd_link_info *info,
+                   bfd_vma offset)
+{
+  struct spu_link_hash_table *htab = spu_hash_table (info);
+  asection *sfixup = htab->sfixup;
+  bfd_vma qaddr = offset & ~(bfd_vma) 15;
+  bfd_vma bit = ((bfd_vma) 8) >> ((offset & 15) >> 2);
+  if (sfixup->reloc_count == 0)
+    {
+      FIXUP_PUT (output_bfd, htab, 0, qaddr | bit);
+      sfixup->reloc_count++;
+    }
+  else
+    {
+      bfd_vma base = FIXUP_GET (output_bfd, htab, sfixup->reloc_count - 1);
+      if (qaddr != (base & ~(bfd_vma) 15))
+       {
+         if ((sfixup->reloc_count + 1) * FIXUP_RECORD_SIZE > sfixup->size)
+           (*_bfd_error_handler) (_("fatal error while creating .fixup"));
+         FIXUP_PUT (output_bfd, htab, sfixup->reloc_count, qaddr | bit);
+         sfixup->reloc_count++;
+       }
+      else
+       FIXUP_PUT (output_bfd, htab, sfixup->reloc_count - 1, base | bit);
+    }
+}
+
 /* Apply RELOCS to CONTENTS of INPUT_SECTION from INPUT_BFD.  */
 
 static int
@@ -4910,6 +4969,16 @@ spu_elf_relocate_section (bfd *output_bfd,
            }
        }
 
+      if (htab->params->emit_fixups && !info->relocatable
+         && (input_section->flags & SEC_ALLOC) != 0
+         && r_type == R_SPU_ADDR32)
+       {
+         bfd_vma offset;
+         offset = rel->r_offset + input_section->output_section->vma
+                  + input_section->output_offset;
+         spu_elf_emit_fixup (output_bfd, info, offset);
+       }
+
       if (unresolved_reloc)
        ;
       else if (r_type == R_SPU_PPU32 || r_type == R_SPU_PPU64)
@@ -5305,6 +5374,72 @@ spu_elf_modify_program_headers (bfd *abfd, struct bfd_link_info *info)
   return TRUE;
 }
 
+bfd_boolean
+spu_elf_size_sections (bfd * output_bfd, struct bfd_link_info *info)
+{
+  struct spu_link_hash_table *htab = spu_hash_table (info);
+  if (htab->params->emit_fixups)
+    {
+      asection *sfixup = htab->sfixup;
+      int fixup_count = 0;
+      bfd *ibfd;
+      size_t size;
+
+      for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+       {
+         asection *isec;
+
+         if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
+           continue;
+
+         /* Walk over each section attached to the input bfd.  */
+         for (isec = ibfd->sections; isec != NULL; isec = isec->next)
+           {
+             Elf_Internal_Rela *internal_relocs, *irelaend, *irela;
+             bfd_vma base_end;
+
+             /* If there aren't any relocs, then there's nothing more
+                to do.  */
+             if ((isec->flags & SEC_RELOC) == 0
+                 || isec->reloc_count == 0)
+               continue;
+
+             /* Get the relocs.  */
+             internal_relocs =
+               _bfd_elf_link_read_relocs (ibfd, isec, NULL, NULL,
+                                          info->keep_memory);
+             if (internal_relocs == NULL)
+               return FALSE;
+
+             /* 1 quadword can contain up to 4 R_SPU_ADDR32
+                relocations.  They are stored in a single word by
+                saving the upper 28 bits of the address and setting the
+                lower 4 bits to a bit mask of the words that have the
+                relocation.  BASE_END keeps track of the next quadword. */
+             irela = internal_relocs;
+             irelaend = irela + isec->reloc_count;
+             base_end = 0;
+             for (; irela < irelaend; irela++)
+               if (ELF32_R_TYPE (irela->r_info) == R_SPU_ADDR32
+                   && irela->r_offset >= base_end)
+                 {
+                   base_end = (irela->r_offset & ~(bfd_vma) 15) + 16;
+                   fixup_count++;
+                 }
+           }
+       }
+
+      /* We always have a NULL fixup as a sentinel */
+      size = (fixup_count + 1) * FIXUP_RECORD_SIZE;
+      if (!bfd_set_section_size (output_bfd, sfixup, size))
+       return FALSE;
+      sfixup->contents = (bfd_byte *) bfd_zalloc (info->input_bfds, size);
+      if (sfixup->contents == NULL)
+       return FALSE;
+    }
+  return TRUE;
+}
+
 #define TARGET_BIG_SYM         bfd_elf32_spu_vec
 #define TARGET_BIG_NAME                "elf32-spu"
 #define ELF_ARCH               bfd_arch_spu
index fc4d84e..a31c76e 100644 (file)
@@ -57,6 +57,9 @@ struct spu_elf_params
   /* Set if non-icache code should be allowed in icache lines.  */
   unsigned int non_ia_text : 1;
 
+  /* Set when the .fixup section should be generated. */
+  unsigned int emit_fixups : 1;
+
   /* Range of valid addresses for loadable sections.  */
   bfd_vma local_store_lo;
   bfd_vma local_store_hi;
@@ -114,6 +117,7 @@ extern void spu_elf_plugin (int);
 extern bfd_boolean spu_elf_open_builtin_lib (bfd **,
                                             const struct _ovl_stream *);
 extern bfd_boolean spu_elf_create_sections (struct bfd_link_info *);
+extern bfd_boolean spu_elf_size_sections (bfd *, struct bfd_link_info *);
 extern int spu_elf_find_overlays (struct bfd_link_info *);
 extern int spu_elf_size_stubs (struct bfd_link_info *);
 extern void spu_elf_place_overlay_data (struct bfd_link_info *);
index a3774ec..742b567 100644 (file)
@@ -1,3 +1,14 @@
+2009-08-05  Trevor Smigiel  <Trevor_Smigiel@playstation.sony.com>
+
+       * emulparams/elf32_spu.sh (OTHER_READONLY_SECTIONS): Add .fixup
+       section and __fixup_start symbol.
+       * emultempl/spuelf.em (params): Initialize emit_fixups member.
+       (spu_before_allocation): Call spu_elf_size_sections.
+       (OPTION_SPU_EMIT_FIXUPS): Define.
+       (PARSE_AND_LIST_LONGOPTS): Add --emit-fixups.
+       (PARSE_AND_LIST_ARGS_CASES): Handle --emit-fixups.
+       * ld.texinfo (--emit-fixups): Document.
+
 2009-08-04  Alan Modra  <amodra@bigpond.net.au>
 
        PR 10474
index 1ed58c3..6993ca7 100644 (file)
@@ -20,3 +20,8 @@ DATA_ADDR="ALIGN(${MAXPAGESIZE})"
 OTHER_BSS_SECTIONS=".toe ALIGN(128) : { *(.toe) } = 0"
 OTHER_SECTIONS=".note.spu_name 0 : { KEEP(*(.note.spu_name)) }
   ._ea 0 : { KEEP(*(._ea)) KEEP(*(._ea.*)) }"
+OTHER_READONLY_SECTIONS="
+  .fixup ${RELOCATING-0} : {
+    PROVIDE (__fixup_start = .);
+    KEEP(*(.fixup))
+  }"
index 1b549ad..1f4fbec 100644 (file)
@@ -37,7 +37,7 @@ static struct spu_elf_params params =
   &spu_elf_load_ovl_mgr,
   &spu_elf_open_overlay_script,
   &spu_elf_relink,
-  0, ovly_normal, 0, 0, 0, 0, 0, 0, 0,
+  0, ovly_normal, 0, 0, 0, 0, 0, 0, 0, 0,
   0, 0x3ffff,
   1, 0, 16, 0, 0, 2000
 };
@@ -316,6 +316,10 @@ spu_before_allocation (void)
       lang_reset_memory_regions ();
     }
 
+  if (is_spu_target ()
+      && !link_info.relocatable)
+    spu_elf_size_sections (link_info.output_bfd, &link_info);
+
   gld${EMULATION_NAME}_before_allocation ();
 }
 
@@ -600,6 +604,7 @@ PARSE_AND_LIST_PROLOGUE='
 #define OPTION_SPU_RESERVED_SPACE      (OPTION_SPU_FIXED_SPACE + 1)
 #define OPTION_SPU_EXTRA_STACK         (OPTION_SPU_RESERVED_SPACE + 1)
 #define OPTION_SPU_NO_AUTO_OVERLAY     (OPTION_SPU_EXTRA_STACK + 1)
+#define OPTION_SPU_EMIT_FIXUPS         (OPTION_SPU_NO_AUTO_OVERLAY + 1)
 '
 
 PARSE_AND_LIST_LONGOPTS='
@@ -625,6 +630,7 @@ PARSE_AND_LIST_LONGOPTS='
   { "reserved-space", required_argument, NULL, OPTION_SPU_RESERVED_SPACE },
   { "extra-stack-space", required_argument, NULL, OPTION_SPU_EXTRA_STACK },
   { "no-auto-overlay", optional_argument, NULL, OPTION_SPU_NO_AUTO_OVERLAY },
+  { "emit-fixups", optional_argument, NULL, OPTION_SPU_EMIT_FIXUPS },
 '
 
 PARSE_AND_LIST_OPTIONS='
@@ -812,6 +818,10 @@ PARSE_AND_LIST_ARGS_CASES='
          break;
        }
       break;
+
+    case OPTION_SPU_EMIT_FIXUPS:
+      params.emit_fixups = 1;
+      break;
 '
 
 LDEMUL_AFTER_OPEN=spu_after_open
index d63c14b..1386162 100644 (file)
@@ -1,3 +1,8 @@
+2009-08-05  Trevor Smigiel  <Trevor_Smigiel@playstation.sony.com>
+
+       * ld-spu/fixup.d: New.
+       * ld-spu/fixup.s: New.
+
 2009-08-05  Nathan Sidwell  <nathan@codesourcery.com>
 
        * ld-arm/cortex-a8-far-1.s: New.
diff --git a/ld/testsuite/ld-spu/fixup.d b/ld/testsuite/ld-spu/fixup.d
new file mode 100644 (file)
index 0000000..39f731b
--- /dev/null
@@ -0,0 +1,20 @@
+#source: fixup.s
+#ld: --emit-fixups
+#objdump: -s 
+
+.*elf32-spu
+
+Contents of section .text:
+ 0000 00000000                             ....            
+Contents of section .fixup:
+ 0004 0000008b 00000091 000000c1 00000000  ................
+Contents of section .data:
+ 0080 000000d0 00000000 00000000 000000c0  ................
+ 0090 00000000 00000000 00000000 000000b0  ................
+ 00a0 00000001 00000000 00000000 00000000  ................
+ 00b0 00000002 00000000 00000000 00000000  ................
+ 00c0 00000000 00000000 00000000 00000080  ................
+Contents of section .note.spu_name:
+.*
+.*
+#pass
diff --git a/ld/testsuite/ld-spu/fixup.s b/ld/testsuite/ld-spu/fixup.s
new file mode 100644 (file)
index 0000000..c0fd6db
--- /dev/null
@@ -0,0 +1,24 @@
+ .global _end
+ .global _start
+ .global glob
+ .global after
+ .global before
+ .weak undef
+
+ .section .text,"ax"
+_start:
+ stop
+
+
+ .data
+ .p2align 4
+before:
+ .long _end, 0, _start, after
+ .long 0, 0, 0, glob
+loc:
+ .long 1,0,0,0
+glob:
+ .long 2,0,0,0
+after:
+ .long 0, 0, 0, before
+