diff options
author | Alan Modra <amodra@gmail.com> | 2009-01-12 00:23:58 +0000 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2009-01-12 00:23:58 +0000 |
commit | cd4a7468c909dc8135cdf6198d596869defcdabe (patch) | |
tree | 71d35b68ba5984de4d54c75253ff12e97a6c710f | |
parent | 2c0fbbe09e6b2dec0e8fa68f133773e0970bda89 (diff) | |
download | gdb-cd4a7468c909dc8135cdf6198d596869defcdabe.zip gdb-cd4a7468c909dc8135cdf6198d596869defcdabe.tar.gz gdb-cd4a7468c909dc8135cdf6198d596869defcdabe.tar.bz2 |
bfd/
* elf32-spu.c (struct spu_link_hash_table): Add init, line_size_log2,
num_lines_log2.
(struct got_entry): Add br_addr.
(struct call_info): Add priority.
(struct function_info): Add lr_store and sp_adjust.
(spu_elf_setup): Init line_size_log2 and num_lines_log2.
(spu_elf_find_overlays): For soft-icache, mark any section within cache
area as an overlay, and check that no other overlays exist. Look up
icache overlay manager entry sym.
(BRA_STUBS, BRA, BRASL): Define.
(enum _stub_type): Replace ovl_stub with call_ovl_stub and br*_ovl_stub.
(needs_ovl_stub): Adjust for soft-icache. Return priority encoded
in branch insn.
(count_stub, build_stub): Support soft-icache.
(build_spuear_stubs, process_stubs): Adjust build_stub call.
(spu_elf_size_stubs): Size soft-icache stubs.
(overlay_index): New function.
(spu_elf_build_stubs): Make static. Support soft-icache.
(spu_elf_check_vma): Don't turn off auto_overlay if soft-icache.
(find_function_stack_adjust): Save lr store and stack adjust insn
offsets.
(maybe_insert_function): Adjust find_function_stack_adjust call.
(mark_functions_via_relocs): Retrieve priority.
(remove_cycles): Only warn about pruned arcs when stack_analysis.
(sort_calls): Sort by priority first.
(mark_overlay_section): Ignore .ovl.init.
(sum_stack): Only print when stack_analysis.
(print_one_overlay_section): New function, extracted from..
(spu_elf_auto_overlay): ..here. Support soft-icache overlays.
(spu_elf_stack_analysis): Only print when htab->stack_analysis.
(spu_elf_final_link): Call spu_elf_stack_analysis for lrlive
analysis. Call spu_elf_build_stubs.
(spu_elf_relocate_section): For soft-icache encode overlay index
into addresses.
(spu_elf_output_symbol_hook): Support soft-icache.
(spu_elf_modify_program_headers: Likewise.
* elf32-spu.h (struct spu_elf_params): Add lrlive_analysis. Rename
num_regions to num_lines. Add line_size and max_branch.
(enum _ovly_flavour): Add ovly_soft_icache.
(spu_elf_build_stubs): Delete.
gas/
* config/tc-spu.c (md_pseudo_table): Add "brinfo".
(brinfo): New var.
(md_assemble): Poke brinfo into branch instructions.
(spu_brinfo): New function.
(md_apply_fix): Don't assume insn fields start off at zero, mask
them to remove possible brinfo.
ld/
* emultempl/spuelf.em (params): Init new fields.
(num_lines_set, line_size_set, icache_mgr, icache_mgr_stream): New vars.
(spu_place_special_section): Adjust placement for soft-icache. Pad
soft-icache section to a fixed size. Clear addr_tree.
(spu_elf_load_ovl_mgr): Support soft-icache. Map overlay manager
sections a little more intelligently.
(gld${EMULATION_NAME}_finish): Don't call spu_elf_build_stubs.
(OPTION_SPU_NUM_LINES): Rename from OPTION_SPU_NUM_REGIONS.
(OPTION_SPU_SOFT_ICACHE, OPTION_SPU_LINE_SIZE): Define.
(OPTION_SPU_LRLIVE): Define.
(PARSE_AND_LIST_LONGOPTS): Add new soft-icache options.
(PARSE_AND_LIST_OPTIONS): Likewise.
(PARSE_AND_LIST_ARGS_CASES): Handle them.
* emultempl/spu_icache.S: Dummy file.
* emultempl/spu_icache.o_c: Regenerate.
* Makefile.am (eelf32_spu.c): Depend on spu_icache.o_c.
(spu_icache.o_c): Add rule to build.
(CLEANFILES): Zap temp files.
(EXTRA_DIST): Add spu_icache.o_c.
* Makefile.in: Regenerate.
ld/testsuite/
* ld-spu/ovl.d: Allow for absolute branches in stubs.
* ld-spu/ovl2.d: Likewise.
-rw-r--r-- | bfd/ChangeLog | 43 | ||||
-rw-r--r-- | bfd/elf32-spu.c | 1186 | ||||
-rw-r--r-- | bfd/elf32-spu.h | 9 | ||||
-rw-r--r-- | gas/ChangeLog | 9 | ||||
-rw-r--r-- | gas/config/tc-spu.c | 165 | ||||
-rw-r--r-- | ld/ChangeLog | 23 | ||||
-rw-r--r-- | ld/Makefile.am | 13 | ||||
-rw-r--r-- | ld/Makefile.in | 13 | ||||
-rw-r--r-- | ld/emultempl/spu_icache.S | 4 | ||||
-rw-r--r-- | ld/emultempl/spu_icache.o_c | 0 | ||||
-rw-r--r-- | ld/emultempl/spuelf.em | 167 | ||||
-rw-r--r-- | ld/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | ld/testsuite/ld-spu/ovl.d | 24 | ||||
-rw-r--r-- | ld/testsuite/ld-spu/ovl2.d | 18 |
14 files changed, 1302 insertions, 377 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 477cad0..83d6a20 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,46 @@ +2009-01-12 Alan Modra <amodra@bigpond.net.au> + + * elf32-spu.c (struct spu_link_hash_table): Add init, line_size_log2, + num_lines_log2. + (struct got_entry): Add br_addr. + (struct call_info): Add priority. + (struct function_info): Add lr_store and sp_adjust. + (spu_elf_setup): Init line_size_log2 and num_lines_log2. + (spu_elf_find_overlays): For soft-icache, mark any section within cache + area as an overlay, and check that no other overlays exist. Look up + icache overlay manager entry sym. + (BRA_STUBS, BRA, BRASL): Define. + (enum _stub_type): Replace ovl_stub with call_ovl_stub and br*_ovl_stub. + (needs_ovl_stub): Adjust for soft-icache. Return priority encoded + in branch insn. + (count_stub, build_stub): Support soft-icache. + (build_spuear_stubs, process_stubs): Adjust build_stub call. + (spu_elf_size_stubs): Size soft-icache stubs. + (overlay_index): New function. + (spu_elf_build_stubs): Make static. Support soft-icache. + (spu_elf_check_vma): Don't turn off auto_overlay if soft-icache. + (find_function_stack_adjust): Save lr store and stack adjust insn + offsets. + (maybe_insert_function): Adjust find_function_stack_adjust call. + (mark_functions_via_relocs): Retrieve priority. + (remove_cycles): Only warn about pruned arcs when stack_analysis. + (sort_calls): Sort by priority first. + (mark_overlay_section): Ignore .ovl.init. + (sum_stack): Only print when stack_analysis. + (print_one_overlay_section): New function, extracted from.. + (spu_elf_auto_overlay): ..here. Support soft-icache overlays. + (spu_elf_stack_analysis): Only print when htab->stack_analysis. + (spu_elf_final_link): Call spu_elf_stack_analysis for lrlive + analysis. Call spu_elf_build_stubs. + (spu_elf_relocate_section): For soft-icache encode overlay index + into addresses. + (spu_elf_output_symbol_hook): Support soft-icache. + (spu_elf_modify_program_headers: Likewise. + * elf32-spu.h (struct spu_elf_params): Add lrlive_analysis. Rename + num_regions to num_lines. Add line_size and max_branch. + (enum _ovly_flavour): Add ovly_soft_icache. + (spu_elf_build_stubs): Delete. + 2009-01-11 Jan Kratochvil <jan.kratochvil@redhat.com> * elflink.c (_bfd_elf_section_already_linked): Handle g++-3.4 diff --git a/bfd/elf32-spu.c b/bfd/elf32-spu.c index 447aa8d..1592c3b 100644 --- a/bfd/elf32-spu.c +++ b/bfd/elf32-spu.c @@ -1,6 +1,6 @@ /* SPU specific support for 32-bit ELF - Copyright 2006, 2007, 2008 Free Software Foundation, Inc. + Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -301,6 +301,7 @@ struct spu_link_hash_table /* Shortcuts to overlay sections. */ asection *ovtab; + asection *init; asection *toe; asection **ovl_sec; @@ -320,6 +321,10 @@ struct spu_link_hash_table /* Total number of overlays. */ unsigned int num_overlays; + /* For soft icache. */ + unsigned int line_size_log2; + unsigned int num_lines_log2; + /* How much memory we have. */ unsigned int local_store; /* Local store --auto-overlay should reserve for non-overlay @@ -345,7 +350,10 @@ struct got_entry { struct got_entry *next; unsigned int ovl; - bfd_vma addend; + union { + bfd_vma addend; + bfd_vma br_addr; + }; bfd_vma stub_addr; }; @@ -360,6 +368,7 @@ struct call_info unsigned int max_depth; unsigned int is_tail : 1; unsigned int is_pasted : 1; + unsigned int priority : 13; }; struct function_info @@ -382,6 +391,10 @@ struct function_info unsigned int call_count; /* Address range of (this part of) function. */ bfd_vma lo, hi; + /* Offset where we found a store of lr, or -1 if none found. */ + bfd_vma lr_store; + /* Offset where we found the stack adjustment insn. */ + bfd_vma sp_adjust; /* Stack usage. */ int stack; /* Distance from root of call tree. Tail and hot/cold branches @@ -415,6 +428,9 @@ struct spu_elf_stack_info struct function_info fun[1]; }; +static struct function_info *find_function (asection *, bfd_vma, + struct bfd_link_info *); + /* Create a spu ELF linker hash table. */ static struct bfd_link_hash_table * @@ -449,6 +465,8 @@ spu_elf_setup (struct bfd_link_info *info, struct spu_elf_params *params) { struct spu_link_hash_table *htab = spu_hash_table (info); htab->params = params; + htab->line_size_log2 = bfd_log2 (htab->params->line_size); + htab->num_lines_log2 = bfd_log2 (htab->params->num_lines); } /* Find the symbol for the given R_SYMNDX in IBFD and set *HP and *SYMP @@ -597,6 +615,7 @@ spu_elf_find_overlays (struct bfd_link_info *info) unsigned int i, n, ovl_index, num_buf; asection *s; bfd_vma ovl_end; + const char *ovly_mgr_entry; if (info->output_bfd->section_count < 2) return FALSE; @@ -622,51 +641,149 @@ spu_elf_find_overlays (struct bfd_link_info *info) /* Sort them by vma. */ qsort (alloc_sec, n, sizeof (*alloc_sec), sort_sections); - /* Look for overlapping vmas. Any with overlap must be overlays. - Count them. Also count the number of overlay regions. */ ovl_end = alloc_sec[0]->vma + alloc_sec[0]->size; - for (ovl_index = 0, num_buf = 0, i = 1; i < n; i++) + if (htab->params->ovly_flavour == ovly_soft_icache) { - s = alloc_sec[i]; - if (s->vma < ovl_end) + /* Look for an overlapping vma to find the first overlay section. */ + bfd_vma vma_start = 0; + bfd_vma lma_start = 0; + + for (i = 1; i < n; i++) { - asection *s0 = alloc_sec[i - 1]; + s = alloc_sec[i]; + if (s->vma < ovl_end) + { + asection *s0 = alloc_sec[i - 1]; + vma_start = s0->vma; + lma_start = s0->lma; + ovl_end = (s0->vma + + ((bfd_vma) 1 + << (htab->num_lines_log2 + htab->line_size_log2))); + --i; + break; + } + else + ovl_end = s->vma + s->size; + } - if (spu_elf_section_data (s0)->u.o.ovl_index == 0) + /* Now find any sections within the cache area. */ + for (ovl_index = 0, num_buf = 0; i < n; i++) + { + s = alloc_sec[i]; + if (s->vma >= ovl_end) + break; + + /* A section in an overlay area called .ovl.init is not + an overlay, in the sense that it might be loaded in + by the overlay manager, but rather the initial + section contents for the overlay buffer. */ + if (strncmp (s->name, ".ovl.init", 9) != 0) { - alloc_sec[ovl_index] = s0; - spu_elf_section_data (s0)->u.o.ovl_index = ++ovl_index; - spu_elf_section_data (s0)->u.o.ovl_buf = ++num_buf; + num_buf = ((s->vma - vma_start) >> htab->line_size_log2) + 1; + if (((s->vma - vma_start) & (htab->params->line_size - 1)) + || ((s->lma - lma_start) & (htab->params->line_size - 1))) + { + info->callbacks->einfo (_("%X%P: overlay section %A " + "does not start on a cache line.\n"), + s); + return FALSE; + } + else if (s->size > htab->params->line_size) + { + info->callbacks->einfo (_("%X%P: overlay section %A " + "is larger than a cache line.\n"), + s); + return FALSE; + } + + alloc_sec[ovl_index++] = s; + spu_elf_section_data (s)->u.o.ovl_index + = ((s->lma - lma_start) >> htab->line_size_log2) + 1; + spu_elf_section_data (s)->u.o.ovl_buf = num_buf; } - alloc_sec[ovl_index] = s; - spu_elf_section_data (s)->u.o.ovl_index = ++ovl_index; - spu_elf_section_data (s)->u.o.ovl_buf = num_buf; - if (s0->vma != s->vma) + } + + /* Ensure there are no more overlay sections. */ + for ( ; i < n; i++) + { + s = alloc_sec[i]; + if (s->vma < ovl_end) { - info->callbacks->einfo (_("%X%P: overlay sections %A and %A " - "do not start at the same address.\n"), - s0, s); + info->callbacks->einfo (_("%X%P: overlay section %A " + "is not in cache area.\n"), + alloc_sec[i-1]); return FALSE; } - if (ovl_end < s->vma + s->size) + else + ovl_end = s->vma + s->size; + } + } + else + { + /* Look for overlapping vmas. Any with overlap must be overlays. + Count them. Also count the number of overlay regions. */ + for (ovl_index = 0, num_buf = 0, i = 1; i < n; i++) + { + s = alloc_sec[i]; + if (s->vma < ovl_end) + { + asection *s0 = alloc_sec[i - 1]; + + if (spu_elf_section_data (s0)->u.o.ovl_index == 0) + { + ++num_buf; + if (strncmp (s0->name, ".ovl.init", 9) != 0) + { + alloc_sec[ovl_index] = s0; + spu_elf_section_data (s0)->u.o.ovl_index = ++ovl_index; + spu_elf_section_data (s0)->u.o.ovl_buf = num_buf; + } + else + ovl_end = s->vma + s->size; + } + if (strncmp (s->name, ".ovl.init", 9) != 0) + { + alloc_sec[ovl_index] = s; + spu_elf_section_data (s)->u.o.ovl_index = ++ovl_index; + spu_elf_section_data (s)->u.o.ovl_buf = num_buf; + if (s0->vma != s->vma) + { + info->callbacks->einfo (_("%X%P: overlay sections %A " + "and %A do not start at the " + "same address.\n"), + s0, s); + return FALSE; + } + if (ovl_end < s->vma + s->size) + ovl_end = s->vma + s->size; + } + } + else ovl_end = s->vma + s->size; } - else - ovl_end = s->vma + s->size; } htab->num_overlays = ovl_index; htab->num_buf = num_buf; htab->ovl_sec = alloc_sec; - htab->ovly_load = elf_link_hash_lookup (&htab->elf, "__ovly_load", + ovly_mgr_entry = "__ovly_load"; + if (htab->params->ovly_flavour == ovly_soft_icache) + ovly_mgr_entry = "__icache_br_handler"; + htab->ovly_load = elf_link_hash_lookup (&htab->elf, ovly_mgr_entry, FALSE, FALSE, FALSE); - htab->ovly_return = elf_link_hash_lookup (&htab->elf, "__ovly_return", - FALSE, FALSE, FALSE); + if (htab->params->ovly_flavour != ovly_soft_icache) + htab->ovly_return = elf_link_hash_lookup (&htab->elf, "__ovly_return", + FALSE, FALSE, FALSE); return ovl_index != 0; } -#define BRSL 0x33000000 +/* Non-zero to use bra in overlay stubs rather than br. */ +#define BRA_STUBS 0 + +#define BRA 0x30000000 +#define BRASL 0x31000000 #define BR 0x32000000 +#define BRSL 0x33000000 #define NOP 0x40200000 #define LNOP 0x00200000 #define ILA 0x42000000 @@ -736,7 +853,15 @@ maybe_needs_stubs (asection *input_section) enum _stub_type { no_stub, - ovl_stub, + call_ovl_stub, + br000_ovl_stub, + br001_ovl_stub, + br010_ovl_stub, + br011_ovl_stub, + br100_ovl_stub, + br101_ovl_stub, + br110_ovl_stub, + br111_ovl_stub, nonovl_stub, stub_error }; @@ -756,8 +881,9 @@ needs_ovl_stub (struct elf_link_hash_entry *h, struct spu_link_hash_table *htab = spu_hash_table (info); enum elf_spu_reloc_type r_type; unsigned int sym_type; - bfd_boolean branch; + bfd_boolean branch, hint, call; enum _stub_type ret = no_stub; + bfd_byte insn[4]; if (sym_sec == NULL || sym_sec->output_section == bfd_abs_section_ptr @@ -775,14 +901,9 @@ needs_ovl_stub (struct elf_link_hash_entry *h, makes setjmp/longjmp between overlays work. */ if (strncmp (h->root.root.string, "setjmp", 6) == 0 && (h->root.root.string[6] == '\0' || h->root.root.string[6] == '@')) - ret = ovl_stub; + ret = call_ovl_stub; } - /* Usually, symbols in non-overlay sections don't need stubs. */ - if (spu_elf_section_data (sym_sec->output_section)->u.o.ovl_index == 0 - && !htab->params->non_overlay_stubs) - return ret; - if (h != NULL) sym_type = h->type; else @@ -790,10 +911,10 @@ needs_ovl_stub (struct elf_link_hash_entry *h, r_type = ELF32_R_TYPE (irela->r_info); branch = FALSE; + hint = FALSE; + call = FALSE; if (r_type == R_SPU_REL16 || r_type == R_SPU_ADDR16) { - bfd_byte insn[4]; - if (contents == NULL) { contents = insn; @@ -806,10 +927,12 @@ needs_ovl_stub (struct elf_link_hash_entry *h, else contents += irela->r_offset; - if (is_branch (contents) || is_hint (contents)) + branch = is_branch (contents); + hint = is_hint (contents); + if (branch || hint) { - branch = TRUE; - if ((contents[0] & 0xfd) == 0x31 + call = (contents[0] & 0xfd) == 0x31; + if (call && sym_type != STT_FUNC && contents != insn) { @@ -840,20 +963,45 @@ needs_ovl_stub (struct elf_link_hash_entry *h, } } - if (sym_type != STT_FUNC - && !branch - && (sym_sec->flags & SEC_CODE) == 0) + if ((!branch && htab->params->ovly_flavour == ovly_soft_icache) + || (sym_type != STT_FUNC + && !(branch || hint) + && (sym_sec->flags & SEC_CODE) == 0)) + return no_stub; + + /* Usually, symbols in non-overlay sections don't need stubs. */ + if (spu_elf_section_data (sym_sec->output_section)->u.o.ovl_index == 0 + && !htab->params->non_overlay_stubs) return ret; /* A reference from some other section to a symbol in an overlay section needs a stub. */ if (spu_elf_section_data (sym_sec->output_section)->u.o.ovl_index != spu_elf_section_data (input_section->output_section)->u.o.ovl_index) - ret = ovl_stub; + { + if (call || sym_type == STT_FUNC) + ret = call_ovl_stub; + else + { + ret = br000_ovl_stub; + + if (branch) + { + unsigned int lrlive = (contents[1] & 0x70) >> 4; + ret += lrlive; + } + } + } /* If this insn isn't a branch then we are possibly taking the - address of a function and passing it out somehow. */ - return !branch && sym_type == STT_FUNC ? nonovl_stub : ret; + address of a function and passing it out somehow. Soft-icache code + always generates inline code to do indirect branches. */ + if (!(branch || hint) + && sym_type == STT_FUNC + && htab->params->ovly_flavour != ovly_soft_icache) + ret = nonovl_stub; + + return ret; } static bfd_boolean @@ -891,6 +1039,12 @@ count_stub (struct spu_link_hash_table *htab, head = elf_local_got_ents (ibfd) + ELF32_R_SYM (irela->r_info); } + if (htab->params->ovly_flavour == ovly_soft_icache) + { + htab->stub_count[ovl] += 1; + return TRUE; + } + addend = 0; if (irela != NULL) addend = irela->r_addend; @@ -963,10 +1117,19 @@ ovl_stub_size (enum _ovly_flavour ovly_flavour) ila $78,ovl_number lnop ila $79,target_address - br __ovly_load */ + br __ovly_load + + Software icache stubs are: + + .word target_index + .word target_ia; + .word lrlive_branchlocalstoreaddr; + brasl $75,__icache_br_handler + .quad xor_pattern +*/ static bfd_boolean -build_stub (struct spu_link_hash_table *htab, +build_stub (struct bfd_link_info *info, bfd *ibfd, asection *isec, enum _stub_type stub_type, @@ -975,10 +1138,12 @@ build_stub (struct spu_link_hash_table *htab, bfd_vma dest, asection *dest_sec) { - unsigned int ovl, dest_ovl; + struct spu_link_hash_table *htab = spu_hash_table (info); + unsigned int ovl, dest_ovl, set_id; struct got_entry *g, **head; asection *sec; - bfd_vma addend, from, to; + bfd_vma addend, from, to, br_dest, patt; + unsigned int lrlive; ovl = 0; if (stub_type != nonovl_stub) @@ -993,17 +1158,34 @@ build_stub (struct spu_link_hash_table *htab, if (irela != NULL) addend = irela->r_addend; - for (g = *head; g != NULL; g = g->next) - if (g->addend == addend && (g->ovl == ovl || g->ovl == 0)) - break; - if (g == NULL) - abort (); + if (htab->params->ovly_flavour == ovly_soft_icache) + { + g = bfd_malloc (sizeof *g); + if (g == NULL) + return FALSE; + g->ovl = ovl; + g->br_addr = 0; + if (irela != NULL) + g->br_addr = (irela->r_offset + + isec->output_offset + + isec->output_section->vma); + g->next = *head; + *head = g; + } + else + { + for (g = *head; g != NULL; g = g->next) + if (g->addend == addend && (g->ovl == ovl || g->ovl == 0)) + break; + if (g == NULL) + abort (); - if (g->ovl == 0 && ovl != 0) - return TRUE; + if (g->ovl == 0 && ovl != 0) + return TRUE; - if (g->stub_addr != (bfd_vma) -1) - return TRUE; + if (g->stub_addr != (bfd_vma) -1) + return TRUE; + } sec = htab->stub_sec[ovl]; dest += dest_sec->output_offset + dest_sec->output_section->vma; @@ -1029,17 +1211,138 @@ build_stub (struct spu_link_hash_table *htab, sec->contents + sec->size + 4); bfd_put_32 (sec->owner, ILA + ((dest << 7) & 0x01ffff80) + 79, sec->contents + sec->size + 8); - bfd_put_32 (sec->owner, BR + (((to - (from + 12)) << 5) & 0x007fff80), - sec->contents + sec->size + 12); + if (!BRA_STUBS) + bfd_put_32 (sec->owner, BR + (((to - (from + 12)) << 5) & 0x007fff80), + sec->contents + sec->size + 12); + else + bfd_put_32 (sec->owner, BRA + ((to << 5) & 0x007fff80), + sec->contents + sec->size + 12); break; case ovly_compact: - bfd_put_32 (sec->owner, BRSL + (((to - from) << 5) & 0x007fff80) + 75, - sec->contents + sec->size); + if (!BRA_STUBS) + bfd_put_32 (sec->owner, BRSL + (((to - from) << 5) & 0x007fff80) + 75, + sec->contents + sec->size); + else + bfd_put_32 (sec->owner, BRASL + ((to << 5) & 0x007fff80) + 75, + sec->contents + sec->size); bfd_put_32 (sec->owner, (dest & 0x3ffff) | (dest_ovl << 18), sec->contents + sec->size + 4); break; + case ovly_soft_icache: + lrlive = 0; + if (stub_type == nonovl_stub) + ; + else if (stub_type == call_ovl_stub) + /* A brsl makes lr live and *(*sp+16) is live. + Tail calls have the same liveness. */ + lrlive = 5; + else if (!htab->params->lrlive_analysis) + /* Assume stack frame and lr save. */ + lrlive = 1; + else if (irela != NULL) + { + /* Analyse branch instructions. */ + struct function_info *caller; + bfd_vma off; + + caller = find_function (isec, irela->r_offset, info); + if (caller->start == NULL) + off = irela->r_offset; + else + { + struct function_info *found = NULL; + + /* Find the earliest piece of this function that + has frame adjusting instructions. We might + see dynamic frame adjustment (eg. for alloca) + in some later piece, but functions using + alloca always set up a frame earlier. Frame + setup instructions are always in one piece. */ + if (caller->lr_store != (bfd_vma) -1 + || caller->sp_adjust != (bfd_vma) -1) + found = caller; + while (caller->start != NULL) + { + caller = caller->start; + if (caller->lr_store != (bfd_vma) -1 + || caller->sp_adjust != (bfd_vma) -1) + found = caller; + } + if (found != NULL) + caller = found; + off = (bfd_vma) -1; + } + + if (off > caller->sp_adjust) + { + if (off > caller->lr_store) + /* Only *(*sp+16) is live. */ + lrlive = 1; + else + /* If no lr save, then we must be in a + leaf function with a frame. + lr is still live. */ + lrlive = 4; + } + else if (off > caller->lr_store) + { + /* Between lr save and stack adjust. */ + lrlive = 3; + /* This should never happen since prologues won't + be split here. */ + BFD_ASSERT (0); + } + else + /* On entry to function. */ + lrlive = 5; + + if (stub_type != br000_ovl_stub + && lrlive != stub_type - br000_ovl_stub) + info->callbacks->einfo (_("%A:0x%v lrlive .brinfo (%u) differs " + "from analysis (%u)\n"), + isec, irela->r_offset, lrlive, + stub_type - br000_ovl_stub); + } + + /* If given lrlive info via .brinfo, use it. */ + if (stub_type > br000_ovl_stub) + lrlive = stub_type - br000_ovl_stub; + + /* The branch that uses this stub goes to stub_addr + 12. We'll + set up an xor pattern that can be used by the icache manager + to modify this branch to go directly to its destination. */ + g->stub_addr += 12; + br_dest = g->stub_addr; + if (irela == NULL) + { + /* Except in the case of _SPUEAR_ stubs, the branch in + question is the one in the stub itself. */ + BFD_ASSERT (stub_type == nonovl_stub); + g->br_addr = g->stub_addr; + br_dest = to; + } + + bfd_put_32 (sec->owner, dest_ovl - 1, + sec->contents + sec->size + 0); + set_id = (dest_ovl - 1) >> htab->num_lines_log2; + bfd_put_32 (sec->owner, (set_id << 18) | (dest & 0x3ffff), + sec->contents + sec->size + 4); + bfd_put_32 (sec->owner, (lrlive << 29) | (g->br_addr & 0x3ffff), + sec->contents + sec->size + 8); + bfd_put_32 (sec->owner, BRASL + ((to << 5) & 0x007fff80) + 75, + sec->contents + sec->size + 12); + patt = dest ^ br_dest; + if (irela != NULL && ELF32_R_TYPE (irela->r_info) == R_SPU_REL16) + patt = (dest - g->br_addr) ^ (br_dest - g->br_addr); + bfd_put_32 (sec->owner, (patt << 5) & 0x007fff80, + sec->contents + sec->size + 16 + (g->br_addr & 0xf)); + if (ovl == 0) + /* Extra space for linked list entries. */ + sec->size += 16; + break; + default: abort (); } @@ -1144,7 +1447,7 @@ build_spuear_stubs (struct elf_link_hash_entry *h, void *inf) && (spu_elf_section_data (sym_sec->output_section)->u.o.ovl_index != 0 || htab->params->non_overlay_stubs)) { - return build_stub (htab, NULL, NULL, nonovl_stub, h, NULL, + return build_stub (info, NULL, NULL, nonovl_stub, h, NULL, h->root.u.def.value, sym_sec); } @@ -1256,7 +1559,7 @@ process_stubs (struct bfd_link_info *info, bfd_boolean build) else dest = sym->st_value; dest += irela->r_addend; - if (!build_stub (htab, ibfd, isec, stub_type, h, irela, + if (!build_stub (info, ibfd, isec, stub_type, h, irela, dest, sym_sec)) goto error_ret_free_internal; } @@ -1291,6 +1594,7 @@ spu_elf_size_stubs (struct bfd_link_info *info) flagword flags; unsigned int i; asection *stub; + const char *ovout; if (!process_stubs (info, FALSE)) return 0; @@ -1318,6 +1622,9 @@ spu_elf_size_stubs (struct bfd_link_info *info) htab->params->ovly_flavour + 3)) return 0; stub->size = htab->stub_count[0] * ovl_stub_size (htab->params->ovly_flavour); + if (htab->params->ovly_flavour == ovly_soft_icache) + /* Extra space for linked list entries. */ + stub->size += htab->stub_count[0] * 16; (*htab->params->place_spu_section) (stub, NULL, ".text"); for (i = 0; i < htab->num_overlays; ++i) @@ -1334,19 +1641,6 @@ spu_elf_size_stubs (struct bfd_link_info *info) (*htab->params->place_spu_section) (stub, osec, NULL); } - /* htab->ovtab consists of two arrays. - . struct { - . u32 vma; - . u32 size; - . u32 file_off; - . u32 buf; - . } _ovly_table[]; - . - . struct { - . u32 mapped; - . } _ovly_buf_table[]; - . */ - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY); htab->ovtab = bfd_make_section_anyway_with_flags (ibfd, ".ovtab", flags); @@ -1354,14 +1648,51 @@ spu_elf_size_stubs (struct bfd_link_info *info) || !bfd_set_section_alignment (ibfd, htab->ovtab, 4)) return 0; - htab->ovtab->size = htab->num_overlays * 16 + 16 + htab->num_buf * 4; - (*htab->params->place_spu_section) (htab->ovtab, NULL, ".data"); + if (htab->params->ovly_flavour == ovly_soft_icache) + { + /* Space for icache manager tables. + a) Tag array, one quadword per cache line. + b) Linked list elements, max_branch per line quadwords. + c) Indirect branch descriptors, 8 quadwords. */ + htab->ovtab->size = 16 * (((1 + htab->params->max_branch) + << htab->num_lines_log2) + + 8); + + htab->init = bfd_make_section_anyway_with_flags (ibfd, ".ovini", flags); + if (htab->init == NULL + || !bfd_set_section_alignment (ibfd, htab->init, 4)) + return 0; + + htab->init->size = 16; + (*htab->params->place_spu_section) (htab->init, NULL, ".ovl.init"); + } + else + { + /* htab->ovtab consists of two arrays. + . struct { + . u32 vma; + . u32 size; + . u32 file_off; + . u32 buf; + . } _ovly_table[]; + . + . struct { + . u32 mapped; + . } _ovly_buf_table[]; + . */ + + htab->ovtab->size = htab->num_overlays * 16 + 16 + htab->num_buf * 4; + } + ovout = ".data"; + if (htab->params->ovly_flavour == ovly_soft_icache) + ovout = ".data.icache"; + (*htab->params->place_spu_section) (htab->ovtab, NULL, ovout); htab->toe = bfd_make_section_anyway_with_flags (ibfd, ".toe", SEC_ALLOC); if (htab->toe == NULL || !bfd_set_section_alignment (ibfd, htab->toe, 4)) return 0; - htab->toe->size = 16; + htab->toe->size = htab->params->ovly_flavour == ovly_soft_icache ? 256 : 16; (*htab->params->place_spu_section) (htab->toe, NULL, ".toe"); return 2; @@ -1413,6 +1744,15 @@ spu_elf_open_builtin_lib (bfd **ovl_bfd, const struct _ovl_stream *stream) return *ovl_bfd != NULL; } +static unsigned int +overlay_index (asection *sec) +{ + if (sec == NULL + || sec->output_section == bfd_abs_section_ptr) + return 0; + return spu_elf_section_data (sec->output_section)->u.o.ovl_index; +} + /* Define an STT_OBJECT symbol. */ static struct elf_link_hash_entry * @@ -1456,7 +1796,7 @@ define_ovtab_symbol (struct spu_link_hash_table *htab, const char *name) /* Fill in all stubs and the overlay tables. */ -bfd_boolean +static bfd_boolean spu_elf_build_stubs (struct bfd_link_info *info) { struct spu_link_hash_table *htab = spu_hash_table (info); @@ -1480,8 +1820,17 @@ spu_elf_build_stubs (struct bfd_link_info *info) htab->stub_sec[i]->size = 0; } - h = elf_link_hash_lookup (&htab->elf, "__ovly_load", FALSE, FALSE, FALSE); - htab->ovly_load = h; + h = htab->ovly_load; + if (h == NULL) + { + const char *ovly_mgr_entry = "__ovly_load"; + + if (htab->params->ovly_flavour == ovly_soft_icache) + ovly_mgr_entry = "__icache_br_handler"; + h = elf_link_hash_lookup (&htab->elf, ovly_mgr_entry, + FALSE, FALSE, FALSE); + htab->ovly_load = h; + } BFD_ASSERT (h != NULL && (h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) @@ -1496,8 +1845,13 @@ spu_elf_build_stubs (struct bfd_link_info *info) return FALSE; } - h = elf_link_hash_lookup (&htab->elf, "__ovly_return", FALSE, FALSE, FALSE); - htab->ovly_return = h; + h = htab->ovly_return; + if (h == NULL && htab->params->ovly_flavour != ovly_soft_icache) + { + h = elf_link_hash_lookup (&htab->elf, "__ovly_return", + FALSE, FALSE, FALSE); + htab->ovly_return = h; + } /* Fill in all the stubs. */ process_stubs (info, TRUE); @@ -1522,61 +1876,154 @@ spu_elf_build_stubs (struct bfd_link_info *info) htab->stub_sec[i]->rawsize = 0; } + if (htab->ovtab == NULL || htab->ovtab->size == 0) + return TRUE; + htab->ovtab->contents = bfd_zalloc (htab->ovtab->owner, htab->ovtab->size); if (htab->ovtab->contents == NULL) return FALSE; - /* Write out _ovly_table. */ p = htab->ovtab->contents; - /* set low bit of .size to mark non-overlay area as present. */ - p[7] = 1; - obfd = htab->ovtab->output_section->owner; - for (s = obfd->sections; s != NULL; s = s->next) + if (htab->params->ovly_flavour == ovly_soft_icache) { - unsigned int ovl_index = spu_elf_section_data (s)->u.o.ovl_index; +#define BI_HANDLER "__icache_ptr___icache_bi_handler0" + char name[sizeof (BI_HANDLER)]; + bfd_vma off, icache_base, linklist, bihand; + + h = define_ovtab_symbol (htab, "__icache_tagbase"); + if (h == NULL) + return FALSE; + h->root.u.def.value = 0; + h->size = 16 << htab->num_lines_log2; + off = h->size; + icache_base = htab->ovl_sec[0]->vma; + linklist = (htab->ovtab->output_section->vma + + htab->ovtab->output_offset + + off); + for (i = 0; i < htab->params->num_lines; i++) + { + bfd_vma line_end = icache_base + ((i + 1) << htab->line_size_log2); + bfd_vma stub_base = line_end - htab->params->max_branch * 32; + bfd_vma link_elem = linklist + i * htab->params->max_branch * 16; + bfd_vma locator = link_elem - stub_base / 2; + + bfd_put_32 (htab->ovtab->owner, locator, p + 4); + bfd_put_16 (htab->ovtab->owner, link_elem, p + 8); + bfd_put_16 (htab->ovtab->owner, link_elem, p + 10); + bfd_put_16 (htab->ovtab->owner, link_elem, p + 12); + bfd_put_16 (htab->ovtab->owner, link_elem, p + 14); + p += 16; + } + + h = define_ovtab_symbol (htab, "__icache_linked_list"); + if (h == NULL) + return FALSE; + h->root.u.def.value = off; + h->size = htab->params->max_branch << (htab->num_lines_log2 + 4); + off += h->size; + p += h->size; + + h = elf_link_hash_lookup (&htab->elf, "__icache_bi_handler", + FALSE, FALSE, FALSE); + bihand = 0; + if (h != NULL + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && h->def_regular) + bihand = (h->root.u.def.value + + h->root.u.def.section->output_offset + + h->root.u.def.section->output_section->vma); + memcpy (name, BI_HANDLER, sizeof (BI_HANDLER)); + for (i = 0; i < 8; i++) + { + name[sizeof (BI_HANDLER) - 2] = '0' + i; + h = define_ovtab_symbol (htab, name); + if (h == NULL) + return FALSE; + h->root.u.def.value = off; + h->size = 16; + bfd_put_32 (htab->ovtab->owner, bihand, p); + bfd_put_32 (htab->ovtab->owner, i << 28, p + 8); + p += 16; + off += 16; + } + + h = define_ovtab_symbol (htab, "__icache_base"); + if (h == NULL) + return FALSE; + h->root.u.def.value = 0; + h->root.u.def.section = htab->ovl_sec[0]; + h->size = htab->num_buf << htab->line_size_log2; - if (ovl_index != 0) + if (htab->init != NULL && htab->init->size != 0) { - unsigned long off = ovl_index * 16; - unsigned int ovl_buf = spu_elf_section_data (s)->u.o.ovl_buf; + htab->init->contents = bfd_zalloc (htab->init->owner, + htab->init->size); + if (htab->init->contents == NULL) + return FALSE; - bfd_put_32 (htab->ovtab->owner, s->vma, p + off); - bfd_put_32 (htab->ovtab->owner, (s->size + 15) & -16, p + off + 4); - /* file_off written later in spu_elf_modify_program_headers. */ - bfd_put_32 (htab->ovtab->owner, ovl_buf, p + off + 12); + h = define_ovtab_symbol (htab, "__icache_fileoff"); + if (h == NULL) + return FALSE; + h->root.u.def.value = 0; + h->root.u.def.section = htab->init; + h->size = 8; } } + else + { + /* Write out _ovly_table. */ + /* set low bit of .size to mark non-overlay area as present. */ + p[7] = 1; + obfd = htab->ovtab->output_section->owner; + for (s = obfd->sections; s != NULL; s = s->next) + { + unsigned int ovl_index = spu_elf_section_data (s)->u.o.ovl_index; - h = define_ovtab_symbol (htab, "_ovly_table"); - if (h == NULL) - return FALSE; - h->root.u.def.value = 16; - h->size = htab->num_overlays * 16; + if (ovl_index != 0) + { + unsigned long off = ovl_index * 16; + unsigned int ovl_buf = spu_elf_section_data (s)->u.o.ovl_buf; + + bfd_put_32 (htab->ovtab->owner, s->vma, p + off); + bfd_put_32 (htab->ovtab->owner, (s->size + 15) & -16, + p + off + 4); + /* file_off written later in spu_elf_modify_program_headers. */ + bfd_put_32 (htab->ovtab->owner, ovl_buf, p + off + 12); + } + } - h = define_ovtab_symbol (htab, "_ovly_table_end"); - if (h == NULL) - return FALSE; - h->root.u.def.value = htab->num_overlays * 16 + 16; - h->size = 0; + h = define_ovtab_symbol (htab, "_ovly_table"); + if (h == NULL) + return FALSE; + h->root.u.def.value = 16; + h->size = htab->num_overlays * 16; - h = define_ovtab_symbol (htab, "_ovly_buf_table"); - if (h == NULL) - return FALSE; - h->root.u.def.value = htab->num_overlays * 16 + 16; - h->size = htab->num_buf * 4; + h = define_ovtab_symbol (htab, "_ovly_table_end"); + if (h == NULL) + return FALSE; + h->root.u.def.value = htab->num_overlays * 16 + 16; + h->size = 0; - h = define_ovtab_symbol (htab, "_ovly_buf_table_end"); - if (h == NULL) - return FALSE; - h->root.u.def.value = htab->num_overlays * 16 + 16 + htab->num_buf * 4; - h->size = 0; + h = define_ovtab_symbol (htab, "_ovly_buf_table"); + if (h == NULL) + return FALSE; + h->root.u.def.value = htab->num_overlays * 16 + 16; + h->size = htab->num_buf * 4; + + h = define_ovtab_symbol (htab, "_ovly_buf_table_end"); + if (h == NULL) + return FALSE; + h->root.u.def.value = htab->num_overlays * 16 + 16 + htab->num_buf * 4; + h->size = 0; + } h = define_ovtab_symbol (htab, "_EAR_"); if (h == NULL) return FALSE; h->root.u.def.section = htab->toe; h->root.u.def.value = 0; - h->size = 16; + h->size = htab->params->ovly_flavour == ovly_soft_icache ? 16 * 16 : 16; return TRUE; } @@ -1606,15 +2053,22 @@ spu_elf_check_vma (struct bfd_link_info *info) return m->sections[i]; /* No need for overlays if it all fits. */ - htab->params->auto_overlay = 0; + if (htab->params->ovly_flavour != ovly_soft_icache) + htab->params->auto_overlay = 0; return NULL; } /* OFFSET in SEC (presumably) is the beginning of a function prologue. - Search for stack adjusting insns, and return the sp delta. */ + Search for stack adjusting insns, and return the sp delta. + If a store of lr is found save the instruction offset to *LR_STORE. + If a stack adjusting instruction is found, save that offset to + *SP_ADJUST. */ static int -find_function_stack_adjust (asection *sec, bfd_vma offset) +find_function_stack_adjust (asection *sec, + bfd_vma offset, + bfd_vma *lr_store, + bfd_vma *sp_adjust) { int reg[128]; @@ -1629,11 +2083,16 @@ find_function_stack_adjust (asection *sec, bfd_vma offset) if (!bfd_get_section_contents (sec->owner, sec, buf, offset, 4)) break; - if (buf[0] == 0x24 /* stqd */) - continue; - rt = buf[3] & 0x7f; ra = ((buf[2] & 0x3f) << 1) | (buf[3] >> 7); + + if (buf[0] == 0x24 /* stqd */) + { + if (rt == 0 /* lr */ && ra == 1 /* sp */) + *lr_store = offset; + continue; + } + /* Partly decoded immediate field. */ imm = (buf[1] << 9) | (buf[2] << 1) | (buf[3] >> 7); @@ -1647,6 +2106,7 @@ find_function_stack_adjust (asection *sec, bfd_vma offset) { if (reg[rt] > 0) break; + *sp_adjust = offset; return reg[rt]; } } @@ -1659,6 +2119,7 @@ find_function_stack_adjust (asection *sec, bfd_vma offset) { if (reg[rt] > 0) break; + *sp_adjust = offset; return reg[rt]; } } @@ -1859,7 +2320,11 @@ maybe_insert_function (asection *sec, sinfo->fun[i].u.sym = sym_h; sinfo->fun[i].lo = off; sinfo->fun[i].hi = off + size; - sinfo->fun[i].stack = -find_function_stack_adjust (sec, off); + sinfo->fun[i].lr_store = -1; + sinfo->fun[i].sp_adjust = -1; + sinfo->fun[i].stack = -find_function_stack_adjust (sec, off, + &sinfo->fun[i].lr_store, + &sinfo->fun[i].sp_adjust); sinfo->num_fun += 1; return &sinfo->fun[i]; } @@ -2079,6 +2544,7 @@ mark_functions_via_relocs (asection *sec, Elf_Internal_Rela *internal_relocs, *irelaend, *irela; Elf_Internal_Shdr *symtab_hdr; void *psyms; + unsigned int priority = 0; static bfd_boolean warned; if (!interesting_section (sec) @@ -2135,6 +2601,12 @@ mark_functions_via_relocs (asection *sec, if (is_branch (insn)) { is_call = (insn[0] & 0xfd) == 0x31; + priority = insn[1] & 0x0f; + priority <<= 8; + priority |= insn[2]; + priority <<= 8; + priority |= insn[3]; + priority >>= 7; if ((sym_sec->flags & (SEC_ALLOC | SEC_LOAD | SEC_CODE)) != (SEC_ALLOC | SEC_LOAD | SEC_CODE)) { @@ -2215,6 +2687,7 @@ mark_functions_via_relocs (asection *sec, return FALSE; callee->is_tail = !is_call; callee->is_pasted = FALSE; + callee->priority = priority; callee->count = 0; if (callee->fun->last_caller != sec) { @@ -2677,7 +3150,10 @@ remove_cycles (struct function_info *fun, } else if (call->fun->marking) { - if (!spu_hash_table (info)->params->auto_overlay) + struct spu_link_hash_table *htab = spu_hash_table (info); + + if (!htab->params->auto_overlay + && htab->params->stack_analysis) { const char *f1 = func_name (fun); const char *f2 = func_name (call->fun); @@ -2754,7 +3230,7 @@ build_call_tree (struct bfd_link_info *info) return for_each_node (mark_detached_root, info, &depth, FALSE); } -/* qsort predicate to sort calls by max_depth then count. */ +/* qsort predicate to sort calls by priority, max_depth then count. */ static int sort_calls (const void *a, const void *b) @@ -2763,6 +3239,10 @@ sort_calls (const void *a, const void *b) struct call_info *const *c2 = b; int delta; + delta = (*c2)->priority - (*c1)->priority; + if (delta != 0) + return delta; + delta = (*c2)->max_depth - (*c1)->max_depth; if (delta != 0) return delta; @@ -2918,9 +3398,10 @@ mark_overlay_section (struct function_info *fun, } /* Don't put entry code into an overlay. The overlay manager needs - a stack! */ + a stack! Also, don't mark .ovl.init as an overlay. */ if (fun->lo + fun->sec->output_offset + fun->sec->output_section->vma - == info->output_bfd->start_address) + == info->output_bfd->start_address + || strncmp (fun->sec->output_section->name, ".ovl.init", 9) == 0) { fun->sec->linker_mark = 0; if (fun->rodata != NULL) @@ -3008,6 +3489,7 @@ collect_lib_sections (struct function_info *fun, size = fun->sec->size; if (fun->rodata) size += fun->rodata->size; + if (size <= lib_param->lib_size) { *lib_param->lib_sections++ = fun->sec; @@ -3345,23 +3827,26 @@ sum_stack (struct function_info *fun, return TRUE; f1 = func_name (fun); - if (!fun->non_root) - info->callbacks->info (_(" %s: 0x%v\n"), f1, (bfd_vma) cum_stack); - info->callbacks->minfo (_("%s: 0x%v 0x%v\n"), - f1, (bfd_vma) stack, (bfd_vma) cum_stack); - - if (has_call) + if (htab->params->stack_analysis) { - info->callbacks->minfo (_(" calls:\n")); - for (call = fun->call_list; call; call = call->next) - if (!call->is_pasted) - { - const char *f2 = func_name (call->fun); - const char *ann1 = call->fun == max ? "*" : " "; - const char *ann2 = call->is_tail ? "t" : " "; + if (!fun->non_root) + info->callbacks->info (_(" %s: 0x%v\n"), f1, (bfd_vma) cum_stack); + info->callbacks->minfo (_("%s: 0x%v 0x%v\n"), + f1, (bfd_vma) stack, (bfd_vma) cum_stack); - info->callbacks->minfo (_(" %s%s %s\n"), ann1, ann2, f2); - } + if (has_call) + { + info->callbacks->minfo (_(" calls:\n")); + for (call = fun->call_list; call; call = call->next) + if (!call->is_pasted) + { + const char *f2 = func_name (call->fun); + const char *ann1 = call->fun == max ? "*" : " "; + const char *ann2 = call->is_tail ? "t" : " "; + + info->callbacks->minfo (_(" %s%s %s\n"), ann1, ann2, f2); + } + } } if (sum_stack_param->emit_stack_syms) @@ -3430,6 +3915,87 @@ sort_bfds (const void *a, const void *b) return strcmp ((*abfd1)->filename, (*abfd2)->filename); } +static unsigned int +print_one_overlay_section (FILE *script, + unsigned int base, + unsigned int count, + unsigned int ovlynum, + unsigned int *ovly_map, + asection **ovly_sections, + struct bfd_link_info *info) +{ + unsigned int j; + + for (j = base; j < count && ovly_map[j] == ovlynum; j++) + { + asection *sec = ovly_sections[2 * j]; + + if (fprintf (script, " %s%c%s (%s)\n", + (sec->owner->my_archive != NULL + ? sec->owner->my_archive->filename : ""), + info->path_separator, + sec->owner->filename, + sec->name) <= 0) + return -1; + if (sec->segment_mark) + { + struct call_info *call = find_pasted_call (sec); + while (call != NULL) + { + struct function_info *call_fun = call->fun; + sec = call_fun->sec; + if (fprintf (script, " %s%c%s (%s)\n", + (sec->owner->my_archive != NULL + ? sec->owner->my_archive->filename : ""), + info->path_separator, + sec->owner->filename, + sec->name) <= 0) + return -1; + for (call = call_fun->call_list; call; call = call->next) + if (call->is_pasted) + break; + } + } + } + + for (j = base; j < count && ovly_map[j] == ovlynum; j++) + { + asection *sec = ovly_sections[2 * j + 1]; + if (sec != NULL + && fprintf (script, " %s%c%s (%s)\n", + (sec->owner->my_archive != NULL + ? sec->owner->my_archive->filename : ""), + info->path_separator, + sec->owner->filename, + sec->name) <= 0) + return -1; + + sec = ovly_sections[2 * j]; + if (sec->segment_mark) + { + struct call_info *call = find_pasted_call (sec); + while (call != NULL) + { + struct function_info *call_fun = call->fun; + sec = call_fun->rodata; + if (sec != NULL + && fprintf (script, " %s%c%s (%s)\n", + (sec->owner->my_archive != NULL + ? sec->owner->my_archive->filename : ""), + info->path_separator, + sec->owner->filename, + sec->name) <= 0) + return -1; + for (call = call_fun->call_list; call; call = call->next) + if (call->is_pasted) + break; + } + } + } + + return j; +} + /* Handle --auto-overlay. */ static void spu_elf_auto_overlay (struct bfd_link_info *) @@ -3449,6 +4015,7 @@ spu_elf_auto_overlay (struct bfd_link_info *info) unsigned int *ovly_map; FILE *script; unsigned int total_overlay_size, overlay_size; + const char *ovly_mgr_entry; struct elf_link_hash_entry *h; struct _mos_param mos_param; struct _uos_param uos_param; @@ -3480,7 +4047,10 @@ spu_elf_auto_overlay (struct bfd_link_info *info) = bfd_get_section_by_name (info->output_bfd, ".interrupt"); htab = spu_hash_table (info); - h = elf_link_hash_lookup (&htab->elf, "__ovly_load", + ovly_mgr_entry = "__ovly_load"; + if (htab->params->ovly_flavour == ovly_soft_icache) + ovly_mgr_entry = "__icache_br_handler"; + h = elf_link_hash_lookup (&htab->elf, ovly_mgr_entry, FALSE, FALSE, FALSE); if (h != NULL && (h->root.type == bfd_link_hash_defined @@ -3539,6 +4109,10 @@ spu_elf_auto_overlay (struct bfd_link_info *info) fixed_size -= sec->size; total_overlay_size += sec->size; } + else if ((sec->flags & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD) + && sec->output_section->owner == info->output_bfd + && strncmp (sec->output_section->name, ".ovl.init", 9) == 0) + fixed_size -= sec->size; if (count != old_count) bfd_arr[bfd_count++] = ibfd; } @@ -3589,11 +4163,32 @@ spu_elf_auto_overlay (struct bfd_link_info *info) fixed_size += htab->non_ovly_stub * ovl_stub_size (htab->params->ovly_flavour); if (fixed_size + mos_param.max_overlay_size <= htab->local_store) { - /* Guess number of overlays. Assuming overlay buffer is on - average only half full should be conservative. */ - ovlynum = total_overlay_size * 2 / (htab->local_store - fixed_size); - /* Space for _ovly_table[], _ovly_buf_table[] and toe. */ - fixed_size += ovlynum * 16 + 16 + 4 + 16; + if (htab->params->ovly_flavour == ovly_soft_icache) + { + /* Stubs in the non-icache area are bigger. */ + fixed_size += htab->non_ovly_stub * 16; + /* Space for icache manager tables. + a) Tag array, one quadword per cache line. + - word 0: ia address of present line, init to zero. + - word 1: link locator. link_elem=stub_addr/2+locator + - halfwords 4-7: head/tail pointers for linked lists. */ + fixed_size += 16 << htab->num_lines_log2; + /* b) Linked list elements, max_branch per line. */ + fixed_size += htab->params->max_branch << (htab->num_lines_log2 + 4); + /* c) Indirect branch descriptors, 8 quadwords. */ + fixed_size += 8 * 16; + /* d) Pointers to __ea backing store, 16 quadwords. */ + fixed_size += 16 * 16; + } + else + { + /* Guess number of overlays. Assuming overlay buffer is on + average only half full should be conservative. */ + ovlynum = (total_overlay_size * 2 * htab->params->num_lines + / (htab->local_store - fixed_size)); + /* Space for _ovly_table[], _ovly_buf_table[] and toe. */ + fixed_size += ovlynum * 16 + 16 + 4 + 16; + } } if (fixed_size + mos_param.max_overlay_size > htab->local_store) @@ -3631,7 +4226,9 @@ spu_elf_auto_overlay (struct bfd_link_info *info) goto err_exit; memset (&dummy_caller, 0, sizeof (dummy_caller)); - overlay_size = (htab->local_store - fixed_size) / htab->params->num_regions; + overlay_size = (htab->local_store - fixed_size) / htab->params->num_lines; + if (htab->params->line_size != 0) + overlay_size = htab->params->line_size; base = 0; ovlynum = 0; while (base < count) @@ -3722,10 +4319,12 @@ spu_elf_auto_overlay (struct bfd_link_info *info) break; } } + if (htab->params->ovly_flavour == ovly_soft_icache + && num_stubs > htab->params->max_branch) + break; if (tmp + num_stubs * ovl_stub_size (htab->params->ovly_flavour) > overlay_size) break; - size = tmp; } @@ -3756,104 +4355,99 @@ spu_elf_auto_overlay (struct bfd_link_info *info) if (fprintf (script, "SECTIONS\n{\n") <= 0) goto file_err; - for (region = 1; region <= htab->params->num_regions; region++) + if (htab->params->ovly_flavour == ovly_soft_icache) { - ovlynum = region; + if (fprintf (script, + " .data.icache ALIGN (16) : { *(.ovtab) *(.data.icache) }\n" + " . = ALIGN (%u);\n" + " .ovl.init : { *(.ovl.init) }\n" + " . = ABSOLUTE (ADDR (.ovl.init));\n", + htab->params->line_size) <= 0) + goto file_err; + base = 0; - while (base < count && ovly_map[base] < ovlynum) - base++; + ovlynum = 1; + while (base < count) + { + unsigned int indx = ovlynum - 1; + unsigned int vma, lma; - if (base == count) - break; + vma = (indx & (htab->num_lines_log2 - 1)) << htab->line_size_log2; + lma = indx << htab->line_size_log2; + + if (fprintf (script, " .ovly%u ABSOLUTE (ADDR (.ovl.init)) + %u " + ": AT (ALIGN (LOADADDR (.ovl.init) + SIZEOF (.ovl.init), 16) + %u) {\n", + ovlynum, vma, lma) <= 0) + goto file_err; + + base = print_one_overlay_section (script, base, count, ovlynum, + ovly_map, ovly_sections, info); + if (base == (unsigned) -1) + goto file_err; + + if (fprintf (script, " }\n") <= 0) + goto file_err; + + ovlynum++; + } - if (fprintf (script, " OVERLAY :\n {\n") <= 0) + if (fprintf (script, " . = ABSOLUTE (ADDR (.ovl.init)) + %u;\n", + 1 << (htab->num_lines_log2 + htab->line_size_log2)) <= 0) + goto file_err; + } + else + { + if (fprintf (script, + " . = ALIGN (16);\n" + " .ovl.init : { *(.ovl.init) }\n" + " . = ABSOLUTE (ADDR (.ovl.init));\n") <= 0) goto file_err; - while (base < count) + for (region = 1; region <= htab->params->num_lines; region++) { - unsigned int j; - - if (fprintf (script, " .ovly%u {\n", ovlynum) <= 0) - goto file_err; + ovlynum = region; + base = 0; + while (base < count && ovly_map[base] < ovlynum) + base++; - for (j = base; j < count && ovly_map[j] == ovlynum; j++) - { - asection *sec = ovly_sections[2 * j]; + if (base == count) + break; - if (fprintf (script, " %s%c%s (%s)\n", - (sec->owner->my_archive != NULL - ? sec->owner->my_archive->filename : ""), - info->path_separator, - sec->owner->filename, - sec->name) <= 0) + if (region == 1) + { + /* We need to set lma since we are overlaying .ovl.init. */ + if (fprintf (script, + " OVERLAY : AT (ALIGN (LOADADDR (.ovl.init) + SIZEOF (.ovl.init), 16))\n {\n") <= 0) + goto file_err; + } + else + { + if (fprintf (script, " OVERLAY :\n {\n") <= 0) goto file_err; - if (sec->segment_mark) - { - struct call_info *call = find_pasted_call (sec); - while (call != NULL) - { - struct function_info *call_fun = call->fun; - sec = call_fun->sec; - if (fprintf (script, " %s%c%s (%s)\n", - (sec->owner->my_archive != NULL - ? sec->owner->my_archive->filename : ""), - info->path_separator, - sec->owner->filename, - sec->name) <= 0) - goto file_err; - for (call = call_fun->call_list; call; call = call->next) - if (call->is_pasted) - break; - } - } } - for (j = base; j < count && ovly_map[j] == ovlynum; j++) + while (base < count) { - asection *sec = ovly_sections[2 * j + 1]; - if (sec != NULL - && fprintf (script, " %s%c%s (%s)\n", - (sec->owner->my_archive != NULL - ? sec->owner->my_archive->filename : ""), - info->path_separator, - sec->owner->filename, - sec->name) <= 0) + if (fprintf (script, " .ovly%u {\n", ovlynum) <= 0) goto file_err; - sec = ovly_sections[2 * j]; - if (sec->segment_mark) - { - struct call_info *call = find_pasted_call (sec); - while (call != NULL) - { - struct function_info *call_fun = call->fun; - sec = call_fun->rodata; - if (sec != NULL - && fprintf (script, " %s%c%s (%s)\n", - (sec->owner->my_archive != NULL - ? sec->owner->my_archive->filename : ""), - info->path_separator, - sec->owner->filename, - sec->name) <= 0) - goto file_err; - for (call = call_fun->call_list; call; call = call->next) - if (call->is_pasted) - break; - } - } + base = print_one_overlay_section (script, base, count, ovlynum, + ovly_map, ovly_sections, info); + if (base == (unsigned) -1) + goto file_err; + + if (fprintf (script, " }\n") <= 0) + goto file_err; + + ovlynum += htab->params->num_lines; + while (base < count && ovly_map[base] < ovlynum) + base++; } - if (fprintf (script, " }\n") <= 0) + if (fprintf (script, " }\n") <= 0) goto file_err; - - base = j; - ovlynum += htab->params->num_regions; - while (base < count && ovly_map[base] < ovlynum) - base++; } - if (fprintf (script, " }\n") <= 0) - goto file_err; } free (ovly_map); @@ -3891,17 +4485,21 @@ spu_elf_stack_analysis (struct bfd_link_info *info) return FALSE; htab = spu_hash_table (info); - info->callbacks->info (_("Stack size for call graph root nodes.\n")); - info->callbacks->minfo (_("\nStack size for functions. " - "Annotations: '*' max stack, 't' tail call\n")); + if (htab->params->stack_analysis) + { + info->callbacks->info (_("Stack size for call graph root nodes.\n")); + info->callbacks->minfo (_("\nStack size for functions. " + "Annotations: '*' max stack, 't' tail call\n")); + } sum_stack_param.emit_stack_syms = htab->params->emit_stack_syms; sum_stack_param.overall_stack = 0; if (!for_each_node (sum_stack, info, &sum_stack_param, TRUE)) return FALSE; - info->callbacks->info (_("Maximum stack required is 0x%v\n"), - (bfd_vma) sum_stack_param.overall_stack); + if (htab->params->stack_analysis) + info->callbacks->info (_("Maximum stack required is 0x%v\n"), + (bfd_vma) sum_stack_param.overall_stack); return TRUE; } @@ -3915,9 +4513,14 @@ spu_elf_final_link (bfd *output_bfd, struct bfd_link_info *info) if (htab->params->auto_overlay) spu_elf_auto_overlay (info); - if (htab->params->stack_analysis + if ((htab->params->stack_analysis + || (htab->params->ovly_flavour == ovly_soft_icache + && htab->params->lrlive_analysis)) && !spu_elf_stack_analysis (info)) - info->callbacks->einfo ("%X%P: stack analysis error: %E\n"); + info->callbacks->einfo ("%X%P: stack/lrlive analysis error: %E\n"); + + if (!spu_elf_build_stubs (info)) + info->callbacks->einfo ("%F%P: can not build overlay stubs: %E\n"); return bfd_elf_final_link (output_bfd, info); } @@ -3974,10 +4577,12 @@ spu_elf_relocate_section (bfd *output_bfd, bfd_boolean emit_these_relocs = FALSE; bfd_boolean is_ea_sym; bfd_boolean stubs; + unsigned int iovl = 0; htab = spu_hash_table (info); stubs = (htab->stub_sec != NULL && maybe_needs_stubs (input_section)); + iovl = overlay_index (input_section); ea = bfd_get_section_by_name (output_bfd, "._ea"); symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; sym_hashes = (struct elf_link_hash_entry **) (elf_sym_hashes (input_bfd)); @@ -3998,6 +4603,7 @@ spu_elf_relocate_section (bfd *output_bfd, bfd_reloc_status_type r; bfd_boolean unresolved_reloc; bfd_boolean warned; + bfd_boolean overlay_encoded; enum _stub_type stub_type; r_symndx = ELF32_R_SYM (rel->r_info); @@ -4082,8 +4688,59 @@ spu_elf_relocate_section (bfd *output_bfd, is_ea_sym = (ea != NULL && sec != NULL && sec->output_section == ea); + overlay_encoded = FALSE; + + /* If this symbol is in an overlay area, we may need to relocate + to the overlay stub. */ + addend = rel->r_addend; + if (stubs + && !is_ea_sym + && (stub_type = needs_ovl_stub (h, sym, sec, input_section, rel, + contents, info)) != no_stub) + { + unsigned int ovl = 0; + struct got_entry *g, **head; + + if (stub_type != nonovl_stub) + ovl = iovl; + + if (h != NULL) + head = &h->got.glist; + else + head = elf_local_got_ents (input_bfd) + r_symndx; - if (r_type == R_SPU_PPU32 || r_type == R_SPU_PPU64) + for (g = *head; g != NULL; g = g->next) + if (htab->params->ovly_flavour == ovly_soft_icache + ? g->br_addr == (rel->r_offset + + input_section->output_offset + + input_section->output_section->vma) + : g->addend == addend && (g->ovl == ovl || g->ovl == 0)) + break; + if (g == NULL) + abort (); + + relocation = g->stub_addr; + addend = 0; + } + else + { + /* For soft icache, encode the overlay index into addresses. */ + if (htab->params->ovly_flavour == ovly_soft_icache + && !is_ea_sym) + { + unsigned int ovl = overlay_index (sec); + if (ovl != 0) + { + unsigned int set_id = (ovl - 1) >> htab->num_lines_log2; + relocation += set_id << 18; + overlay_encoded = set_id != 0; + } + } + } + + if (unresolved_reloc) + ; + else if (r_type == R_SPU_PPU32 || r_type == R_SPU_PPU64) { if (is_ea_sym) { @@ -4101,8 +4758,7 @@ spu_elf_relocate_section (bfd *output_bfd, emit_these_relocs = TRUE; continue; } - - if (is_ea_sym) + else if (is_ea_sym) unresolved_reloc = TRUE; if (unresolved_reloc) @@ -4117,35 +4773,6 @@ spu_elf_relocate_section (bfd *output_bfd, ret = FALSE; } - /* If this symbol is in an overlay area, we may need to relocate - to the overlay stub. */ - addend = rel->r_addend; - if (stubs - && (stub_type = needs_ovl_stub (h, sym, sec, input_section, rel, - contents, info)) != no_stub) - { - unsigned int ovl = 0; - struct got_entry *g, **head; - - if (stub_type != nonovl_stub) - ovl = (spu_elf_section_data (input_section->output_section) - ->u.o.ovl_index); - - if (h != NULL) - head = &h->got.glist; - else - head = elf_local_got_ents (input_bfd) + r_symndx; - - for (g = *head; g != NULL; g = g->next) - if (g->addend == addend && (g->ovl == ovl || g->ovl == 0)) - break; - if (g == NULL) - abort (); - - relocation = g->stub_addr; - addend = 0; - } - r = _bfd_final_link_relocate (howto, input_bfd, input_section, @@ -4159,6 +4786,11 @@ spu_elf_relocate_section (bfd *output_bfd, switch (r) { case bfd_reloc_overflow: + /* FIXME: We don't want to warn on most references + within an overlay to itself, but this may silence a + warning that should be reported. */ + if (overlay_encoded && sec == input_section) + break; if (!((*info->callbacks->reloc_overflow) (info, (h ? &h->root : NULL), sym_name, howto->name, (bfd_vma) 0, input_bfd, input_section, rel->r_offset))) @@ -4248,7 +4880,9 @@ spu_elf_output_symbol_hook (struct bfd_link_info *info, struct got_entry *g; for (g = h->got.glist; g != NULL; g = g->next) - if (g->addend == 0 && g->ovl == 0) + if (htab->params->ovly_flavour == ovly_soft_icache + ? g->br_addr == g->stub_addr + : g->addend == 0 && g->ovl == 0) { sym->st_shndx = (_bfd_elf_section_from_bfd_section (htab->stub_sec[0]->output_section->owner, @@ -4409,7 +5043,8 @@ spu_elf_modify_program_headers (bfd *abfd, struct bfd_link_info *info) /* Mark this as an overlay header. */ phdr[i].p_flags |= PF_OVERLAY; - if (htab->ovtab != NULL && htab->ovtab->size != 0) + if (htab->ovtab != NULL && htab->ovtab->size != 0 + && htab->params->ovly_flavour != ovly_soft_icache) { bfd_byte *p = htab->ovtab->contents; unsigned int off = o * 16 + 8; @@ -4418,6 +5053,13 @@ spu_elf_modify_program_headers (bfd *abfd, struct bfd_link_info *info) bfd_put_32 (htab->ovtab->owner, phdr[i].p_offset, p + off); } } + /* Soft-icache has its file offset put in .ovl.init. */ + if (htab->init != NULL && htab->init->size != 0) + { + bfd_vma val = elf_section_data (htab->ovl_sec[0])->this_hdr.sh_offset; + + bfd_put_32 (htab->init->owner, val, htab->init->contents + 4); + } } /* Round up p_filesz and p_memsz of PT_LOAD segments to multiples diff --git a/bfd/elf32-spu.h b/bfd/elf32-spu.h index 442dd5d..0487d59 100644 --- a/bfd/elf32-spu.h +++ b/bfd/elf32-spu.h @@ -44,6 +44,9 @@ struct spu_elf_params non-overlay regions. */ unsigned int non_overlay_stubs : 1; + /* Set if lr liveness analysis should be done. */ + unsigned int lrlive_analysis : 1; + /* Set if stack size analysis should be done. */ unsigned int stack_analysis : 1; @@ -55,7 +58,9 @@ struct spu_elf_params bfd_vma local_store_hi; /* Control --auto-overlay feature. */ - unsigned int num_regions; + unsigned int num_lines; + unsigned int line_size; + unsigned int max_branch; unsigned int auto_overlay_fixed; unsigned int auto_overlay_reserved; int extra_stack_space; @@ -92,6 +97,7 @@ enum _ovly_flavour { ovly_compact, ovly_normal, + ovly_soft_icache, ovly_none }; @@ -108,5 +114,4 @@ extern bfd_boolean spu_elf_open_builtin_lib (bfd **, extern bfd_boolean spu_elf_create_sections (struct bfd_link_info *); extern bfd_boolean spu_elf_find_overlays (struct bfd_link_info *); extern int spu_elf_size_stubs (struct bfd_link_info *); -extern bfd_boolean spu_elf_build_stubs (struct bfd_link_info *); extern asection *spu_elf_check_vma (struct bfd_link_info *); diff --git a/gas/ChangeLog b/gas/ChangeLog index e544b76..819600f 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,12 @@ +2009-01-12 Alan Modra <amodra@bigpond.net.au> + + * config/tc-spu.c (md_pseudo_table): Add "brinfo". + (brinfo): New var. + (md_assemble): Poke brinfo into branch instructions. + (spu_brinfo): New function. + (md_apply_fix): Don't assume insn fields start off at zero, mask + them to remove possible brinfo. + 2009-01-10 H.J. Lu <hongjiu.lu@intel.com> * doc/c-i386.texi: Reformat. diff --git a/gas/config/tc-spu.c b/gas/config/tc-spu.c index e159e34..0b40a56 100644 --- a/gas/config/tc-spu.c +++ b/gas/config/tc-spu.c @@ -1,6 +1,6 @@ /* spu.c -- Assembler for the IBM Synergistic Processing Unit (SPU) - Copyright 2006, 2007, 2008 Free Software Foundation, Inc. + Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -53,6 +53,7 @@ static const char *get_reg (const char *param, struct spu_insn *insn, int arg, int accept_expr); static int calcop (struct spu_opcode *format, const char *param, struct spu_insn *insn); +static void spu_brinfo (int); static void spu_cons (int); extern char *myname; @@ -82,6 +83,7 @@ const char FLT_CHARS[] = "dDfF"; const pseudo_typeS md_pseudo_table[] = { {"align", s_align_ptwo, 4}, + {"brinfo", spu_brinfo, 0}, {"bss", s_lcomm_bytes, 1}, {"def", s_set, 0}, {"dfloat", float_cons, 'd'}, @@ -104,6 +106,9 @@ const pseudo_typeS md_pseudo_table[] = {0,0,0} }; +/* Bits plugged into branch instruction offset field. */ +unsigned int brinfo; + void md_begin (void) { @@ -342,6 +347,16 @@ md_assemble (char *op) as_warn (_("Treating '%-*s' as a symbol."), (int)(syntax_error_param - d), d); } + if (brinfo != 0 + && (insn.tag <= M_BRASL + || (insn.tag >= M_BRZ && insn.tag <= M_BRHNZ)) + && (insn.opcode & 0x7ff80) == 0 + && (insn.reloc_arg[0] == A_R18 + || insn.reloc_arg[0] == A_S18 + || insn.reloc_arg[1] == A_R18 + || insn.reloc_arg[1] == A_S18)) + insn.opcode |= brinfo << 7; + /* grow the current frag and plop in the opcode */ thisfrag = frag_more (4); @@ -370,6 +385,9 @@ md_assemble (char *op) fixP->tc_fix_data.insn_tag = insn.tag; } dwarf2_emit_insn (4); + + /* .brinfo lasts exactly one instruction. */ + brinfo = 0; } static int @@ -752,6 +770,39 @@ md_create_long_jump (char *ptr, } #endif +/* Handle .brinfo <priority>,<lrlive>. */ +static void +spu_brinfo (int ignore ATTRIBUTE_UNUSED) +{ + addressT priority; + addressT lrlive; + + priority = get_absolute_expression (); + SKIP_WHITESPACE (); + + lrlive = 0; + if (*input_line_pointer == ',') + { + ++input_line_pointer; + lrlive = get_absolute_expression (); + } + + if (priority > 0x1fff) + { + as_bad (_("invalid priority '%lu'"), (unsigned long) priority); + priority = 0; + } + + if (lrlive > 7) + { + as_bad (_("invalid lrlive '%lu'"), (unsigned long) lrlive); + lrlive = 0; + } + + brinfo = (lrlive << 13) | priority; + demand_empty_rest_of_line (); +} + /* Support @ppu on symbols referenced in .int/.long/.word/.quad. */ static void spu_cons (int nbytes) @@ -898,6 +949,7 @@ void md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) { unsigned int res; + unsigned int mask; valueT val = *valP; char *place = fixP->fx_where + fixP->fx_frag->fr_literal; @@ -944,6 +996,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) { fixP->fx_done = 1; res = 0; + mask = 0; if (fixP->tc_fix_data.arg_format > A_P) { int hi = arg_encode[fixP->tc_fix_data.arg_format].hi; @@ -955,84 +1008,94 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) } switch (fixP->fx_r_type) - { - case BFD_RELOC_8: + { + case BFD_RELOC_8: md_number_to_chars (place, val, 1); return; - case BFD_RELOC_16: + case BFD_RELOC_16: md_number_to_chars (place, val, 2); return; - case BFD_RELOC_32: + case BFD_RELOC_32: case BFD_RELOC_32_PCREL: md_number_to_chars (place, val, 4); return; - case BFD_RELOC_64: + case BFD_RELOC_64: md_number_to_chars (place, val, 8); return; - case BFD_RELOC_SPU_IMM7: - res = (val & 0x7f) << 14; - break; + case BFD_RELOC_SPU_IMM7: + res = val << 14; + mask = 0x7f << 14; + break; - case BFD_RELOC_SPU_IMM8: - res = (val & 0xff) << 14; - break; + case BFD_RELOC_SPU_IMM8: + res = val << 14; + mask = 0xff << 14; + break; - case BFD_RELOC_SPU_IMM10: - res = (val & 0x3ff) << 14; - break; + case BFD_RELOC_SPU_IMM10: + res = val << 14; + mask = 0x3ff << 14; + break; - case BFD_RELOC_SPU_IMM10W: - res = (val & 0x3ff0) << 10; - break; + case BFD_RELOC_SPU_IMM10W: + res = val << 10; + mask = 0x3ff0 << 10; + break; - case BFD_RELOC_SPU_IMM16: - res = (val & 0xffff) << 7; - break; + case BFD_RELOC_SPU_IMM16: + res = val << 7; + mask = 0xffff << 7; + break; - case BFD_RELOC_SPU_IMM16W: - res = (val & 0x3fffc) << 5; - break; + case BFD_RELOC_SPU_IMM16W: + res = val << 5; + mask = 0x3fffc << 5; + break; - case BFD_RELOC_SPU_IMM18: - res = (val & 0x3ffff) << 7; - break; + case BFD_RELOC_SPU_IMM18: + res = val << 7; + mask = 0x3ffff << 7; + break; - case BFD_RELOC_SPU_PCREL9a: - res = ((val & 0x1fc) >> 2) | ((val & 0x600) << 14); - break; + case BFD_RELOC_SPU_PCREL9a: + res = ((val & 0x1fc) >> 2) | ((val & 0x600) << 14); + mask = (0x1fc >> 2) | (0x600 << 14); + break; - case BFD_RELOC_SPU_PCREL9b: - res = ((val & 0x1fc) >> 2) | ((val & 0x600) << 5); - break; + case BFD_RELOC_SPU_PCREL9b: + res = ((val & 0x1fc) >> 2) | ((val & 0x600) << 5); + mask = (0x1fc >> 2) | (0x600 << 5); + break; - case BFD_RELOC_SPU_PCREL16: - res = (val & 0x3fffc) << 5; - break; + case BFD_RELOC_SPU_PCREL16: + res = val << 5; + mask = 0x3fffc << 5; + break; case BFD_RELOC_SPU_HI16: - res = (val >> 9) & 0x7fff80; + res = val >> 9; + mask = 0xffff << 7; break; case BFD_RELOC_SPU_LO16: - res = (val << 7) & 0x7fff80; + res = val << 7; + mask = 0xffff << 7; break; - default: - as_bad_where (fixP->fx_file, fixP->fx_line, - _("reloc %d not supported by object file format"), - (int) fixP->fx_r_type); - } - - if (res != 0) - { - place[0] |= (res >> 24) & 0xff; - place[1] |= (res >> 16) & 0xff; - place[2] |= (res >> 8) & 0xff; - place[3] |= (res) & 0xff; - } + default: + as_bad_where (fixP->fx_file, fixP->fx_line, + _("reloc %d not supported by object file format"), + (int) fixP->fx_r_type); + } + + res &= mask; + place[0] = (place[0] & (~mask >> 24)) | ((res >> 24) & 0xff); + place[1] = (place[1] & (~mask >> 16)) | ((res >> 16) & 0xff); + place[2] = (place[2] & (~mask >> 8)) | ((res >> 8) & 0xff); + place[3] = (place[3] & ~mask) | (res & 0xff); } } diff --git a/ld/ChangeLog b/ld/ChangeLog index 747633c..30ed039 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,26 @@ +2009-01-12 Alan Modra <amodra@bigpond.net.au> + + * emultempl/spuelf.em (params): Init new fields. + (num_lines_set, line_size_set, icache_mgr, icache_mgr_stream): New vars. + (spu_place_special_section): Adjust placement for soft-icache. Pad + soft-icache section to a fixed size. Clear addr_tree. + (spu_elf_load_ovl_mgr): Support soft-icache. Map overlay manager + sections a little more intelligently. + (gld${EMULATION_NAME}_finish): Don't call spu_elf_build_stubs. + (OPTION_SPU_NUM_LINES): Rename from OPTION_SPU_NUM_REGIONS. + (OPTION_SPU_SOFT_ICACHE, OPTION_SPU_LINE_SIZE): Define. + (OPTION_SPU_LRLIVE): Define. + (PARSE_AND_LIST_LONGOPTS): Add new soft-icache options. + (PARSE_AND_LIST_OPTIONS): Likewise. + (PARSE_AND_LIST_ARGS_CASES): Handle them. + * emultempl/spu_icache.S: Dummy file. + * emultempl/spu_icache.o_c: Regenerate. + * Makefile.am (eelf32_spu.c): Depend on spu_icache.o_c. + (spu_icache.o_c): Add rule to build. + (CLEANFILES): Zap temp files. + (EXTRA_DIST): Add spu_icache.o_c. + * Makefile.in: Regenerate. + 2009-01-08 Kai Tietz <kai.tietz@onevision.com> * pe.em (OPTION_USE_NUL_PREFIXED_IMPORT_TABLES): New. diff --git a/ld/Makefile.am b/ld/Makefile.am index 3423dfc..83d92ec 100644 --- a/ld/Makefile.am +++ b/ld/Makefile.am @@ -753,7 +753,7 @@ eelf32_sparc_vxworks.c: $(srcdir)/emulparams/elf32_sparc_vxworks.sh \ $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} ${GENSCRIPTS} elf32_sparc_vxworks "$(tdir_elf32_sparc_vxworks)" eelf32_spu.c: $(srcdir)/emulparams/elf32_spu.sh $(srcdir)/emultempl/spuelf.em \ - $(srcdir)/emultempl/spu_ovl.o_c \ + $(srcdir)/emultempl/spu_ovl.o_c $(srcdir)/emultempl/spu_icache.o_c \ ldemul-list.h \ $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} ${GENSCRIPTS} elf32_spu "$(tdir_elf32_spu)" @@ -764,6 +764,13 @@ $(srcdir)/emultempl/spu_ovl.o_c: @MAINT@ $(srcdir)/emultempl/spu_ovl.S ../gas/as-new -o spu_ovl.o spu_ovl.s; \ ../binutils/bin2c <spu_ovl.o >$@; \ fi +$(srcdir)/emultempl/spu_icache.o_c: @MAINT@ $(srcdir)/emultempl/spu_icache.S + if ../gas/as-new --version \ + | grep 'target.*spu' >/dev/null 2>/dev/null; then \ + cpp -DOVLY_IRQ_SAVE $(srcdir)/emultempl/spu_icache.S spu_icache.s; \ + ../gas/as-new -o spu_icache.o spu_icache.s; \ + ../binutils/bin2c <spu_icache.o >$@; \ + fi eelf32_i860.c: $(srcdir)/emulparams/elf32_i860.sh \ $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} ${GENSCRIPTS} elf32_i860 "$(tdir_elf32_i860)" @@ -1844,7 +1851,7 @@ MOSTLYCLEANFILES = $(STAGESTUFF) ld1$(EXEEXT) ld2$(EXEEXT) ld3$(EXEEXT) \ ldemul-list.h crtbegin.o crtend.o ld.log ld.sum mostlyclean-local: -rm -rf tmpdir -CLEANFILES = dep.sed DEP DEPA DEP1 DEP2 spu_ovl.s spu_ovl.o +CLEANFILES = dep.sed DEP DEPA DEP1 DEP2 spu_ovl.s spu_ovl.o spu_icache.s spu_icache.o .PHONY: install-html install-html-am install-html-recursive @@ -1924,7 +1931,7 @@ install-data-local: install-info # Stuff that should be included in a distribution. The diststuff # target is run by the taz target in ../Makefile.in. EXTRA_DIST = ldgram.c ldgram.h ldlex.c emultempl/spu_ovl.o_c \ - deffilep.c deffilep.h $(man_MANS) + emultempl/spu_icache.o_c deffilep.c deffilep.h $(man_MANS) diststuff: info $(EXTRA_DIST) all: info ld.1 diff --git a/ld/Makefile.in b/ld/Makefile.in index 6f3ae8b..3da3450 100644 --- a/ld/Makefile.in +++ b/ld/Makefile.in @@ -739,13 +739,13 @@ CONFIG_STATUS_DEPENDENCIES = $(srcdir)/configure.host $(srcdir)/configure.tgt \ MOSTLYCLEANFILES = $(STAGESTUFF) ld1$(EXEEXT) ld2$(EXEEXT) ld3$(EXEEXT) \ ldemul-list.h crtbegin.o crtend.o ld.log ld.sum -CLEANFILES = dep.sed DEP DEPA DEP1 DEP2 spu_ovl.s spu_ovl.o +CLEANFILES = dep.sed DEP DEPA DEP1 DEP2 spu_ovl.s spu_ovl.o spu_icache.s spu_icache.o html__strip_dir = `echo $$p | sed -e 's|^.*/||'`; # Stuff that should be included in a distribution. The diststuff # target is run by the taz target in ../Makefile.in. EXTRA_DIST = ldgram.c ldgram.h ldlex.c emultempl/spu_ovl.o_c \ - deffilep.c deffilep.h $(man_MANS) + emultempl/spu_icache.o_c deffilep.c deffilep.h $(man_MANS) DISTCLEANFILES = tdirs site.exp site.bak stringify.sed $(am__append_1) all: config.h @@ -1597,7 +1597,7 @@ eelf32_sparc_vxworks.c: $(srcdir)/emulparams/elf32_sparc_vxworks.sh \ $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} ${GENSCRIPTS} elf32_sparc_vxworks "$(tdir_elf32_sparc_vxworks)" eelf32_spu.c: $(srcdir)/emulparams/elf32_spu.sh $(srcdir)/emultempl/spuelf.em \ - $(srcdir)/emultempl/spu_ovl.o_c \ + $(srcdir)/emultempl/spu_ovl.o_c $(srcdir)/emultempl/spu_icache.o_c \ ldemul-list.h \ $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} ${GENSCRIPTS} elf32_spu "$(tdir_elf32_spu)" @@ -1608,6 +1608,13 @@ $(srcdir)/emultempl/spu_ovl.o_c: @MAINT@ $(srcdir)/emultempl/spu_ovl.S ../gas/as-new -o spu_ovl.o spu_ovl.s; \ ../binutils/bin2c <spu_ovl.o >$@; \ fi +$(srcdir)/emultempl/spu_icache.o_c: @MAINT@ $(srcdir)/emultempl/spu_icache.S + if ../gas/as-new --version \ + | grep 'target.*spu' >/dev/null 2>/dev/null; then \ + cpp -DOVLY_IRQ_SAVE $(srcdir)/emultempl/spu_icache.S spu_icache.s; \ + ../gas/as-new -o spu_icache.o spu_icache.s; \ + ../binutils/bin2c <spu_icache.o >$@; \ + fi eelf32_i860.c: $(srcdir)/emulparams/elf32_i860.sh \ $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} ${GENSCRIPTS} elf32_i860 "$(tdir_elf32_i860)" diff --git a/ld/emultempl/spu_icache.S b/ld/emultempl/spu_icache.S new file mode 100644 index 0000000..be7d523 --- /dev/null +++ b/ld/emultempl/spu_icache.S @@ -0,0 +1,4 @@ + .text + .global __icache_br_handler +__icache_br_handler: + stop diff --git a/ld/emultempl/spu_icache.o_c b/ld/emultempl/spu_icache.o_c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/ld/emultempl/spu_icache.o_c diff --git a/ld/emultempl/spuelf.em b/ld/emultempl/spuelf.em index bfabb8b..f72690d 100644 --- a/ld/emultempl/spuelf.em +++ b/ld/emultempl/spuelf.em @@ -1,5 +1,5 @@ # This shell script emits a C file. -*- C -*- -# Copyright 2006, 2007, 2008 Free Software Foundation, Inc. +# Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc. # # This file is part of the GNU Binutils. # @@ -37,11 +37,13 @@ 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, ovly_normal, 0, 0, 0, 0, 0, 0, 0x3ffff, - 1, 0, 0, 2000 + 1, 0, 16, 0, 0, 2000 }; +static unsigned int num_lines_set = 0; +static unsigned int line_size_set = 0; static char *auto_overlay_file = 0; int my_argc; char **my_argv; @@ -52,7 +54,20 @@ EOF if ! cat ${srcdir}/emultempl/spu_ovl.o_c >> e${EMULATION_NAME}.c then echo >&2 "Missing ${srcdir}/emultempl/spu_ovl.o_c" - echo >&2 "You must build gas/as-new with --target=spu to build spu_ovl.o" + echo >&2 "You must build gas/as-new with --target=spu" + exit 1 +fi + +fragment <<EOF +}; + +static const char icache_mgr[] = { +EOF + +if ! cat ${srcdir}/emultempl/spu_icache.o_c >> e${EMULATION_NAME}.c +then + echo >&2 "Missing ${srcdir}/emultempl/spu_icache.o_c" + echo >&2 "You must build gas/as-new with --target=spu" exit 1 fi @@ -64,6 +79,11 @@ static const struct _ovl_stream ovl_mgr_stream = { ovl_mgr + sizeof (ovl_mgr) }; +static const struct _ovl_stream icache_mgr_stream = { + icache_mgr, + icache_mgr + sizeof (icache_mgr) +}; + static int is_spu_target (void) @@ -96,7 +116,8 @@ spu_after_open (void) } /* If O is NULL, add section S at the end of output section OUTPUT_NAME. - If O is not NULL, add section S at the beginning of output section O. + If O is not NULL, add section S at the beginning of output section O, + except for soft-icache which adds to the end. Really, we should be duplicating ldlang.c map_input_to_output_sections logic here, ie. using the linker script to find where the section @@ -115,8 +136,12 @@ spu_place_special_section (asection *s, asection *o, const char *output_name) output_name = o->name; os = lang_output_section_find (output_name); if (os == NULL) - gld${EMULATION_NAME}_place_orphan (s, output_name, 0); - else if (o != NULL && os->children.head != NULL) + { + os = gld${EMULATION_NAME}_place_orphan (s, output_name, 0); + os->addr_tree = NULL; + } + else if (params.ovly_flavour != ovly_soft_icache + && o != NULL && os->children.head != NULL) { lang_statement_list_type add; @@ -126,7 +151,21 @@ spu_place_special_section (asection *s, asection *o, const char *output_name) os->children.head = add.head; } else - lang_add_section (&os->children, s, os); + { + if (params.ovly_flavour == ovly_soft_icache && o != NULL) + { + /* Pad this stub section so that it finishes at the + end of the icache line. */ + etree_type *e_size; + lang_statement_list_type *save = stat_ptr; + + stat_ptr = &os->children; + e_size = exp_intop (params.line_size - s->size); + lang_add_assignment (exp_assop ('=', ".", e_size)); + stat_ptr = save; + } + lang_add_section (&os->children, s, os); + } s->output_section->size += s->size; } @@ -137,10 +176,19 @@ static bfd_size_type spu_elf_load_ovl_mgr (void) { struct elf_link_hash_entry *h; + const char *ovly_mgr_entry; + const struct _ovl_stream *mgr_stream; bfd_size_type total = 0; + ovly_mgr_entry = "__ovly_load"; + mgr_stream = &ovl_mgr_stream; + if (params.ovly_flavour == ovly_soft_icache) + { + ovly_mgr_entry = "__icache_br_handler"; + mgr_stream = &icache_mgr_stream; + } h = elf_link_hash_lookup (elf_hash_table (&link_info), - "__ovly_load", FALSE, FALSE, FALSE); + ovly_mgr_entry, FALSE, FALSE, FALSE); if (h != NULL && (h->root.type == bfd_link_hash_defined @@ -149,7 +197,7 @@ spu_elf_load_ovl_mgr (void) { /* User supplied __ovly_load. */ } - else if (ovl_mgr_stream.start == ovl_mgr_stream.end) + else if (mgr_stream->start == mgr_stream->end) einfo ("%F%P: no built-in overlay manager\n"); else { @@ -159,7 +207,7 @@ spu_elf_load_ovl_mgr (void) lang_input_file_is_file_enum, NULL); - if (!spu_elf_open_builtin_lib (&ovl_is->the_bfd, &ovl_mgr_stream)) + if (!spu_elf_open_builtin_lib (&ovl_is->the_bfd, mgr_stream)) einfo ("%X%P: can not open built-in overlay manager: %E\n"); else { @@ -168,13 +216,38 @@ spu_elf_load_ovl_mgr (void) if (!load_symbols (ovl_is, NULL)) einfo ("%X%P: can not load built-in overlay manager: %E\n"); - /* Map overlay manager sections to output sections. */ + /* Map overlay manager sections to output sections. + First try for a matching output section name, if that + fails then try mapping .abc.xyz to .abc, otherwise map + to .text. */ for (in = ovl_is->the_bfd->sections; in != NULL; in = in->next) if ((in->flags & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD)) { - total += in->size; - spu_place_special_section (in, NULL, ".text"); + const char *oname = in->name; + if (strncmp (in->name, ".ovl.init", 9) != 0) + { + total += in->size; + if (!lang_output_section_find (oname)) + { + lang_output_section_statement_type *os = NULL; + char *p = strchr (oname + 1, '.'); + if (p != NULL) + { + size_t len = p - oname; + p = memcpy (xmalloc (len + 1), oname, len); + p[len] = '\0'; + os = lang_output_section_find (p); + free (p); + } + if (os != NULL) + oname = os->name; + else + oname = ".text"; + } + } + + spu_place_special_section (in, NULL, oname); } } } @@ -338,9 +411,6 @@ gld${EMULATION_NAME}_finish (void) } else if (params.auto_overlay) einfo ("%P: --auto-overlay ignored with zero local store range\n"); - - if (!spu_elf_build_stubs (&link_info)) - einfo ("%F%P: can not build overlay stubs: %E\n"); } finish_default (); @@ -520,8 +590,11 @@ PARSE_AND_LIST_PROLOGUE=' #define OPTION_SPU_AUTO_OVERLAY (OPTION_SPU_STACK_SYMS + 1) #define OPTION_SPU_AUTO_RELINK (OPTION_SPU_AUTO_OVERLAY + 1) #define OPTION_SPU_OVERLAY_RODATA (OPTION_SPU_AUTO_RELINK + 1) -#define OPTION_SPU_NUM_REGIONS (OPTION_SPU_OVERLAY_RODATA + 1) -#define OPTION_SPU_FIXED_SPACE (OPTION_SPU_NUM_REGIONS + 1) +#define OPTION_SPU_SOFT_ICACHE (OPTION_SPU_OVERLAY_RODATA + 1) +#define OPTION_SPU_LINE_SIZE (OPTION_SPU_SOFT_ICACHE + 1) +#define OPTION_SPU_NUM_LINES (OPTION_SPU_LINE_SIZE + 1) +#define OPTION_SPU_LRLIVE (OPTION_SPU_NUM_LINES + 1) +#define OPTION_SPU_FIXED_SPACE (OPTION_SPU_LRLIVE + 1) #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) @@ -529,6 +602,10 @@ PARSE_AND_LIST_PROLOGUE=' PARSE_AND_LIST_LONGOPTS=' { "plugin", no_argument, NULL, OPTION_SPU_PLUGIN }, + { "soft-icache", no_argument, NULL, OPTION_SPU_SOFT_ICACHE }, + { "lrlive-analysis", no_argument, NULL, OPTION_SPU_LRLIVE }, + { "num-lines", required_argument, NULL, OPTION_SPU_NUM_LINES }, + { "line-size", required_argument, NULL, OPTION_SPU_LINE_SIZE }, { "no-overlays", no_argument, NULL, OPTION_SPU_NO_OVERLAYS }, { "emit-stub-syms", no_argument, NULL, OPTION_SPU_STUB_SYMS }, { "extra-overlay-stubs", no_argument, NULL, OPTION_SPU_NON_OVERLAY_STUBS }, @@ -538,7 +615,8 @@ PARSE_AND_LIST_LONGOPTS=' { "auto-overlay", optional_argument, NULL, OPTION_SPU_AUTO_OVERLAY }, { "auto-relink", no_argument, NULL, OPTION_SPU_AUTO_RELINK }, { "overlay-rodata", no_argument, NULL, OPTION_SPU_OVERLAY_RODATA }, - { "num-regions", required_argument, NULL, OPTION_SPU_NUM_REGIONS }, + { "num-regions", required_argument, NULL, OPTION_SPU_NUM_LINES }, + { "region-size", required_argument, NULL, OPTION_SPU_LINE_SIZE }, { "fixed-space", required_argument, NULL, OPTION_SPU_FIXED_SPACE }, { "reserved-space", required_argument, NULL, OPTION_SPU_RESERVED_SPACE }, { "extra-stack-space", required_argument, NULL, OPTION_SPU_EXTRA_STACK }, @@ -560,11 +638,16 @@ PARSE_AND_LIST_OPTIONS=' --overlay-rodata Place read-only data with associated function\n\ code in overlays.\n\ --num-regions Number of overlay buffers (default 1).\n\ + --region-size Size of overlay buffers (default 0, auto).\n\ --fixed-space=bytes Local store for non-overlay code and data.\n\ --reserved-space=bytes Local store for stack and heap. If not specified\n\ ld will estimate stack size and assume no heap.\n\ --extra-stack-space=bytes Space for negative sp access (default 2000) if\n\ - --reserved-space not given.\n" + --reserved-space not given.\n\ + --soft-icache Generate software icache overlays.\n\ + --num-lines Number of soft-icache lines (default 32).\n\ + --line-size Size of soft-icache lines (default 1k).\n\ + --lrlive-analysis Scan function prologue for lr liveness.\n" )); ' @@ -624,13 +707,47 @@ PARSE_AND_LIST_ARGS_CASES=' params.auto_overlay |= 4; break; - case OPTION_SPU_NUM_REGIONS: + case OPTION_SPU_SOFT_ICACHE: + params.ovly_flavour = ovly_soft_icache; + if (!num_lines_set) + params.num_lines = 32; + else if ((params.num_lines & -params.num_lines) != params.num_lines) + einfo (_("%P%F: invalid --num-lines/--num-regions `%u'\''\n"), + params.num_lines); + if (!line_size_set) + params.line_size = 1024; + else if ((params.line_size & -params.line_size) != params.line_size) + einfo (_("%P%F: invalid --line-size/--region-size `%u'\''\n"), + params.line_size); + break; + + case OPTION_SPU_LRLIVE: + params.lrlive_analysis = 1; + break; + + case OPTION_SPU_NUM_LINES: + { + char *end; + params.num_lines = strtoul (optarg, &end, 0); + num_lines_set = 1; + if (*end == 0 + && (params.ovly_flavour != ovly_soft_icache + || (params.num_lines & -params.num_lines) == params.num_lines)) + break; + einfo (_("%P%F: invalid --num-lines/--num-regions `%s'\''\n"), optarg); + } + break; + + case OPTION_SPU_LINE_SIZE: { char *end; - params.num_regions = strtoul (optarg, &end, 0); - if (*end == 0) + params.line_size = strtoul (optarg, &end, 0); + line_size_set = 1; + if (*end == 0 + && (params.ovly_flavour != ovly_soft_icache + || (params.line_size & -params.line_size) == params.line_size)) break; - einfo (_("%P%F: invalid --num-regions `%s'\''\n"), optarg); + einfo (_("%P%F: invalid --line-size/--region-size `%s'\''\n"), optarg); } break; diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index 1c8b545..1ba7fcd 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2009-01-12 Alan Modra <amodra@bigpond.net.au> + + * ld-spu/ovl.d: Allow for absolute branches in stubs. + * ld-spu/ovl2.d: Likewise. + 2009-01-11 Jan Kratochvil <jan.kratochvil@redhat.com> * ld-elf/linkoncerdiff.d, ld-elf/linkoncerdiff1.s, diff --git a/ld/testsuite/ld-spu/ovl.d b/ld/testsuite/ld-spu/ovl.d index 9d34a11..42d00b7 100644 --- a/ld/testsuite/ld-spu/ovl.d +++ b/ld/testsuite/ld-spu/ovl.d @@ -29,64 +29,64 @@ Disassembly of section \.text: .* bi \$0 #00000130 <00000000\.ovl_call\.f1_a1>: -#.* brsl \$75,.* <__ovly_load>.* +#.* bra?sl \$75,.* <__ovly_load>.* #.*00 04 04 00.* # #00000138 <00000000\.ovl_call\.f2_a1>: -#.* brsl \$75,.* <__ovly_load>.* +#.* bra?sl \$75,.* <__ovly_load>.* #.*00 04 04 04.* # #00000140 <00000000\.ovl_call\.f1_a2>: -#.* brsl \$75,.* <__ovly_load>.* +#.* bra?sl \$75,.* <__ovly_load>.* #.*00 08 04 00.* # #00000148 <00000000\.ovl_call\.f2_a2>: -#.* brsl \$75,.* <__ovly_load>.* +#.* bra?sl \$75,.* <__ovly_load>.* #.*00 08 04 24.* # #00000150 <00000000\.ovl_call\.f4_a1>: -#.* brsl \$75,.* <__ovly_load>.* +#.* bra?sl \$75,.* <__ovly_load>.* #.*00 04 04 10.* # #00000158 <00000000.ovl_call.14:8>: -#.* brsl \$75,.* <__ovly_load>.* +#.* bra?sl \$75,.* <__ovly_load>.* #.*00 08 04 34.* 00000130 <00000000\.ovl_call\.f1_a1>: .* ila \$78,1 .* lnop .* ila \$79,1024 # 400 -.* br .* <__ovly_load>.* +.* bra? .* <__ovly_load>.* 00000140 <00000000\.ovl_call\.f2_a1>: .* ila \$78,1 .* lnop .* ila \$79,1028 # 404 -.* br .* <__ovly_load>.* +.* bra? .* <__ovly_load>.* 00000150 <00000000.ovl_call.f1_a2>: .* ila \$78,2 .* lnop .* ila \$79,1024 # 400 -.* br .* <__ovly_load>.* +.* bra? .* <__ovly_load>.* 00000160 <00000000\.ovl_call\.f2_a2>: .* ila \$78,2 .* lnop .* ila \$79,1060 # 424 -.* br .* <__ovly_load>.* +.* bra? .* <__ovly_load>.* 00000170 <00000000\.ovl_call\.f4_a1>: .* ila \$78,1 .* lnop .* ila \$79,1040 # 410 -.* br .* <__ovly_load>.* +.* bra? .* <__ovly_load>.* 00000180 <00000000.ovl_call.14:8>: .* ila \$78,2 .* lnop .* ila \$79,1076 # 434 -.* br .* <__ovly_load>.* +.* bra? .* <__ovly_load>.* #... [0-9a-f]+ <__ovly_return>: diff --git a/ld/testsuite/ld-spu/ovl2.d b/ld/testsuite/ld-spu/ovl2.d index f9dca19..b509146 100644 --- a/ld/testsuite/ld-spu/ovl2.d +++ b/ld/testsuite/ld-spu/ovl2.d @@ -24,40 +24,40 @@ Disassembly of section \.text: \.\.\. #00000118 <00000000\.ovl_call.f1_a1>: -#.* brsl \$75,.* <__ovly_load>.* +#.* bra?sl \$75,.* <__ovly_load>.* #.*00 04 04 00.* # #00000120 <00000000\.ovl_call.setjmp>: -#.* brsl \$75,.* <__ovly_load>.* +#.* bra?sl \$75,.* <__ovly_load>.* #.*00 00 01 0c.* # #00000128 <_SPUEAR_f1_a2>: -#.* brsl \$75,.* <__ovly_load>.* +#.* bra?sl \$75,.* <__ovly_load>.* #.*00 08 04 00.* 00000120 <00000000\.ovl_call.f1_a1>: .* ila \$78,1 .* lnop .* ila \$79,1040 # 410 -.* br .* <__ovly_load>.* +.* bra? .* <__ovly_load>.* 00000130 <00000000\.ovl_call.setjmp>: .* ila \$78,0 .* lnop .* ila \$79,268 # 10c -.* br .* <__ovly_load>.* +.* bra? .* <__ovly_load>.* 00000140 <00000000\.ovl_call\.13:5>: .* ila \$78,1 .* lnop .* ila \$79,1044 # 414 -.* br .* <__ovly_load>.* +.* bra? .* <__ovly_load>.* 00000150 <_SPUEAR_f1_a2>: .* ila \$78,2 .* lnop .* ila \$79,1040 # 410 -.* br .* <__ovly_load>.* +.* bra? .* <__ovly_load>.* #... Disassembly of section \.ov_a1: @@ -66,7 +66,7 @@ Disassembly of section \.ov_a1: .* ila \$78,2 .* lnop .* ila \$79,1044 # 414 -.* br .* <__ovly_load>.* +.* bra? .* <__ovly_load>.* 00000410 <f1_a1>: .* bi \$0 @@ -83,7 +83,7 @@ Disassembly of section \.ov_a2: .* ila \$78,1 .* lnop .* ila \$79,1056 # 420 -.* br .* <__ovly_load>.* +.* bra? .* <__ovly_load>.* 00000410 <f1_a2>: .* br .* <longjmp>.* |