aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog10
-rw-r--r--bfd/elf32-spu.c135
-rw-r--r--bfd/elf32-spu.h4
-rw-r--r--ld/ChangeLog11
-rw-r--r--ld/emulparams/elf32_spu.sh5
-rw-r--r--ld/emultempl/spuelf.em12
-rw-r--r--ld/testsuite/ChangeLog5
-rw-r--r--ld/testsuite/ld-spu/fixup.d20
-rw-r--r--ld/testsuite/ld-spu/fixup.s24
9 files changed, 225 insertions, 1 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 577918c..a18c0db 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -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.
diff --git a/bfd/elf32-spu.c b/bfd/elf32-spu.c
index b5c90a1..16f9450 100644
--- a/bfd/elf32-spu.c
+++ b/bfd/elf32-spu.c
@@ -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
diff --git a/bfd/elf32-spu.h b/bfd/elf32-spu.h
index fc4d84e..a31c76e 100644
--- a/bfd/elf32-spu.h
+++ b/bfd/elf32-spu.h
@@ -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 *);
diff --git a/ld/ChangeLog b/ld/ChangeLog
index a3774ec..742b567 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -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
diff --git a/ld/emulparams/elf32_spu.sh b/ld/emulparams/elf32_spu.sh
index 1ed58c3..6993ca7 100644
--- a/ld/emulparams/elf32_spu.sh
+++ b/ld/emulparams/elf32_spu.sh
@@ -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))
+ }"
diff --git a/ld/emultempl/spuelf.em b/ld/emultempl/spuelf.em
index 1b549ad..1f4fbec 100644
--- a/ld/emultempl/spuelf.em
+++ b/ld/emultempl/spuelf.em
@@ -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
diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog
index d63c14b..1386162 100644
--- a/ld/testsuite/ChangeLog
+++ b/ld/testsuite/ChangeLog
@@ -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
index 0000000..39f731b
--- /dev/null
+++ b/ld/testsuite/ld-spu/fixup.d
@@ -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
index 0000000..c0fd6db
--- /dev/null
+++ b/ld/testsuite/ld-spu/fixup.s
@@ -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
+