* 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.
This commit is contained in:
Trevor Smigiel 2009-08-05 20:40:34 +00:00
parent 99e008fef7
commit 9cc305ec20
9 changed files with 225 additions and 1 deletions

View 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.

View 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

View 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 *);

View 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

View 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))
}"

View 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

View 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.

View File

@ -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

View File

@ -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