diff options
-rw-r--r-- | bfd/ChangeLog | 10 | ||||
-rw-r--r-- | bfd/elf32-spu.c | 135 | ||||
-rw-r--r-- | bfd/elf32-spu.h | 4 | ||||
-rw-r--r-- | ld/ChangeLog | 11 | ||||
-rw-r--r-- | ld/emulparams/elf32_spu.sh | 5 | ||||
-rw-r--r-- | ld/emultempl/spuelf.em | 12 | ||||
-rw-r--r-- | ld/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | ld/testsuite/ld-spu/fixup.d | 20 | ||||
-rw-r--r-- | ld/testsuite/ld-spu/fixup.s | 24 |
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 + |