X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=bfd%2Felf32-spu.c;h=c6139c9dabff0162a832ef8470f8a9eb9052b4ee;hb=70f101d042e6ba5a823daea2cc26416a70c3a2c4;hp=b5c90a1fa4080b237f19f9988aaab1cb7597ebc1;hpb=6c241aa16fa314856bb368ae96aa6ebba3f19a64;p=pf3gnuchains%2Fpf3gnuchains3x.git diff --git a/bfd/elf32-spu.c b/bfd/elf32-spu.c index b5c90a1fa4..c6139c9dab 100644 --- a/bfd/elf32-spu.c +++ b/bfd/elf32-spu.c @@ -331,19 +331,13 @@ struct spu_link_hash_table /* How much memory we have. */ unsigned int local_store; - /* Local store --auto-overlay should reserve for non-overlay - functions and data. */ - unsigned int overlay_fixed; - /* Local store --auto-overlay should reserve for stack and heap. */ - unsigned int reserved; - /* If reserved is not specified, stack analysis will calculate a value - for the stack. This parameter adjusts that value to allow for - negative sp access (the ABI says 2000 bytes below sp are valid, - and the overlay manager uses some of this area). */ - int extra_stack_space; + /* 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 +552,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 +595,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; } @@ -661,9 +669,10 @@ spu_elf_find_overlays (struct bfd_link_info *info) ovl_end = alloc_sec[0]->vma + alloc_sec[0]->size; if (htab->params->ovly_flavour == ovly_soft_icache) { + unsigned int prev_buf = 0, set_id = 0; + /* 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++) { @@ -672,10 +681,6 @@ spu_elf_find_overlays (struct bfd_link_info *info) { asection *s0 = alloc_sec[i - 1]; vma_start = s0->vma; - if (strncmp (s0->name, ".ovl.init", 9) != 0) - lma_start = s0->lma; - else - lma_start = s->lma; ovl_end = (s0->vma + ((bfd_vma) 1 << (htab->num_lines_log2 + htab->line_size_log2))); @@ -700,8 +705,10 @@ spu_elf_find_overlays (struct bfd_link_info *info) if (strncmp (s->name, ".ovl.init", 9) != 0) { 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))) + set_id = (num_buf == prev_buf)? set_id + 1 : 0; + prev_buf = num_buf; + + if ((s->vma - vma_start) & (htab->params->line_size - 1)) { info->callbacks->einfo (_("%X%P: overlay section %A " "does not start on a cache line.\n"), @@ -720,7 +727,7 @@ spu_elf_find_overlays (struct bfd_link_info *info) alloc_sec[ovl_index++] = s; spu_elf_section_data (s)->u.o.ovl_index - = ((s->lma - lma_start) >> htab->line_size_log2) + 1; + = (set_id << htab->num_lines_log2) + num_buf; spu_elf_section_data (s)->u.o.ovl_buf = num_buf; } } @@ -2676,19 +2683,12 @@ mark_functions_via_relocs (asection *sec, Elf_Internal_Sym *sym; struct elf_link_hash_entry *h; bfd_vma val; - bfd_boolean reject, is_call; + bfd_boolean nonbranch, is_call; struct function_info *caller; struct call_info *callee; - reject = FALSE; r_type = ELF32_R_TYPE (irela->r_info); - if (r_type != R_SPU_REL16 - && r_type != R_SPU_ADDR16) - { - reject = TRUE; - if (!(call_tree && spu_hash_table (info)->params->auto_overlay)) - continue; - } + nonbranch = r_type != R_SPU_REL16 && r_type != R_SPU_ADDR16; r_indx = ELF32_R_SYM (irela->r_info); if (!get_sym_h (&h, &sym, &sym_sec, psyms, r_indx, sec->owner)) @@ -2699,7 +2699,7 @@ mark_functions_via_relocs (asection *sec, continue; is_call = FALSE; - if (!reject) + if (!nonbranch) { unsigned char insn[4]; @@ -2730,14 +2730,13 @@ mark_functions_via_relocs (asection *sec, } else { - reject = TRUE; - if (!(call_tree && spu_hash_table (info)->params->auto_overlay) - || is_hint (insn)) + nonbranch = TRUE; + if (is_hint (insn)) continue; } } - if (reject) + if (nonbranch) { /* For --auto-overlay, count possible stubs we need for function pointer references. */ @@ -2747,8 +2746,20 @@ mark_functions_via_relocs (asection *sec, else sym_type = ELF_ST_TYPE (sym->st_info); if (sym_type == STT_FUNC) - spu_hash_table (info)->non_ovly_stub += 1; - continue; + { + if (call_tree && spu_hash_table (info)->params->auto_overlay) + spu_hash_table (info)->non_ovly_stub += 1; + /* If the symbol type is STT_FUNC then this must be a + function pointer initialisation. */ + continue; + } + /* Ignore data references. */ + if ((sym_sec->flags & (SEC_ALLOC | SEC_LOAD | SEC_CODE)) + != (SEC_ALLOC | SEC_LOAD | SEC_CODE)) + continue; + /* Otherwise we probably have a jump table reloc for + a switch statement or some other reference to a + code label. */ } if (h) @@ -2797,7 +2808,7 @@ mark_functions_via_relocs (asection *sec, callee->is_pasted = FALSE; callee->broken_cycle = FALSE; callee->priority = priority; - callee->count = 1; + callee->count = nonbranch? 0 : 1; if (callee->fun->last_caller != sec) { callee->fun->last_caller = sec; @@ -4143,6 +4154,7 @@ spu_elf_auto_overlay (struct bfd_link_info *info) bfd **bfd_arr; struct elf_segment_map *m; unsigned int fixed_size, lo, hi; + unsigned int reserved; struct spu_link_hash_table *htab; unsigned int base, i, count, bfd_count; unsigned int region, ovlynum; @@ -4178,7 +4190,8 @@ spu_elf_auto_overlay (struct bfd_link_info *info) goto err_exit; htab = spu_hash_table (info); - if (htab->reserved == 0) + reserved = htab->params->auto_overlay_reserved; + if (reserved == 0) { struct _sum_stack_param sum_stack_param; @@ -4186,11 +4199,12 @@ spu_elf_auto_overlay (struct bfd_link_info *info) sum_stack_param.overall_stack = 0; if (!for_each_node (sum_stack, info, &sum_stack_param, TRUE)) goto err_exit; - htab->reserved = sum_stack_param.overall_stack + htab->extra_stack_space; + reserved = (sum_stack_param.overall_stack + + htab->params->extra_stack_space); } /* No need for overlays if everything already fits. */ - if (fixed_size + htab->reserved <= htab->local_store + if (fixed_size + reserved <= htab->local_store && htab->params->ovly_flavour != ovly_soft_icache) { htab->params->auto_overlay = 0; @@ -4303,7 +4317,7 @@ spu_elf_auto_overlay (struct bfd_link_info *info) } free (bfd_arr); - fixed_size += htab->reserved; + fixed_size += reserved; fixed_size += htab->non_ovly_stub * ovl_stub_size (htab->params); if (fixed_size + mos_param.max_overlay_size <= htab->local_store) { @@ -4342,13 +4356,13 @@ spu_elf_auto_overlay (struct bfd_link_info *info) (bfd_vma) mos_param.max_overlay_size); /* Now see if we should put some functions in the non-overlay area. */ - else if (fixed_size < htab->overlay_fixed) + else if (fixed_size < htab->params->auto_overlay_fixed) { unsigned int max_fixed, lib_size; max_fixed = htab->local_store - mos_param.max_overlay_size; - if (max_fixed > htab->overlay_fixed) - max_fixed = htab->overlay_fixed; + if (max_fixed > htab->params->auto_overlay_fixed) + max_fixed = htab->params->auto_overlay_fixed; lib_size = max_fixed - fixed_size; lib_size = auto_ovl_lib_functions (info, lib_size); if (lib_size == (unsigned int) -1) @@ -4387,7 +4401,7 @@ spu_elf_auto_overlay (struct bfd_link_info *info) struct call_info *call, *pasty; struct _spu_elf_section_data *sec_data; struct spu_elf_stack_info *sinfo; - int k; + unsigned int k; /* See whether we can add this section to the current overlay without overflowing our overlay buffer. */ @@ -4407,7 +4421,7 @@ spu_elf_auto_overlay (struct bfd_link_info *info) { /* Pasted sections must stay together, so add their sizes too. */ - struct call_info *pasty = find_pasted_call (sec); + pasty = find_pasted_call (sec); while (pasty != NULL) { struct function_info *call_fun = pasty->fun; @@ -4434,7 +4448,7 @@ spu_elf_auto_overlay (struct bfd_link_info *info) pasty = NULL; sec_data = spu_elf_section_data (sec); sinfo = sec_data->u.i.stack_info; - for (k = 0; k < sinfo->num_fun; ++k) + for (k = 0; k < (unsigned) sinfo->num_fun; ++k) for (call = sinfo->fun[k].call_list; call; call = call->next) if (call->is_pasted) { @@ -4464,7 +4478,6 @@ spu_elf_auto_overlay (struct bfd_link_info *info) num_stubs = 0; for (call = dummy_caller.call_list; call; call = call->next) { - unsigned int k; unsigned int stub_delta = 1; if (htab->params->ovly_flavour == ovly_soft_icache) @@ -4514,13 +4527,12 @@ spu_elf_auto_overlay (struct bfd_link_info *info) script = htab->params->spu_elf_open_overlay_script (); - if (fprintf (script, "SECTIONS\n{\n") <= 0) - goto file_err; - if (htab->params->ovly_flavour == ovly_soft_icache) { + if (fprintf (script, "SECTIONS\n{\n") <= 0) + goto file_err; + if (fprintf (script, - " .data.icache ALIGN (16) : { *(.ovtab) *(.data.icache) }\n" " . = ALIGN (%u);\n" " .ovl.init : { *(.ovl.init) }\n" " . = ABSOLUTE (ADDR (.ovl.init));\n", @@ -4535,10 +4547,10 @@ spu_elf_auto_overlay (struct bfd_link_info *info) unsigned int vma, lma; vma = (indx & (htab->params->num_lines - 1)) << htab->line_size_log2; - lma = indx << htab->line_size_log2; + lma = vma + (((indx >> htab->num_lines_log2) + 1) << 18); if (fprintf (script, " .ovly%u ABSOLUTE (ADDR (.ovl.init)) + %u " - ": AT (ALIGN (LOADADDR (.ovl.init) + SIZEOF (.ovl.init), 16) + %u) {\n", + ": AT (LOADADDR (.ovl.init) + %u) {\n", ovlynum, vma, lma) <= 0) goto file_err; @@ -4556,9 +4568,15 @@ spu_elf_auto_overlay (struct bfd_link_info *info) if (fprintf (script, " . = ABSOLUTE (ADDR (.ovl.init)) + %u;\n", 1 << (htab->num_lines_log2 + htab->line_size_log2)) <= 0) goto file_err; + + if (fprintf (script, "}\nINSERT AFTER .toe;\n") <= 0) + goto file_err; } else { + if (fprintf (script, "SECTIONS\n{\n") <= 0) + goto file_err; + if (fprintf (script, " . = ALIGN (16);\n" " .ovl.init : { *(.ovl.init) }\n" @@ -4610,13 +4628,13 @@ spu_elf_auto_overlay (struct bfd_link_info *info) goto file_err; } + if (fprintf (script, "}\nINSERT BEFORE .text;\n") <= 0) + goto file_err; } free (ovly_map); free (ovly_sections); - if (fprintf (script, "}\nINSERT BEFORE .text;\n") <= 0) - goto file_err; if (fclose (script) != 0) goto file_err; @@ -4718,6 +4736,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 @@ -4847,8 +4907,9 @@ spu_elf_relocate_section (bfd *output_bfd, continue; /* Change "a rt,ra,rb" to "ai rt,ra,0". */ - if (r_type == R_SPU_ADD_PIC && h != NULL - && (h->def_regular || ELF_COMMON_DEF_P (h))) + if (r_type == R_SPU_ADD_PIC + && h != NULL + && !(h->def_regular || ELF_COMMON_DEF_P (h))) { bfd_byte *loc = contents + rel->r_offset; loc[0] = 0x1c; @@ -4910,6 +4971,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) @@ -5181,7 +5252,7 @@ spu_elf_modify_segment_map (bfd *abfd, struct bfd_link_info *info) if ((*p)->p_type == PT_LOAD && (*p)->count == 1 && spu_elf_section_data ((*p)->sections[0])->u.o.ovl_index != 0) { - struct elf_segment_map *m = *p; + m = *p; *p = m->next; *p_overlay = m; p_overlay = &m->next; @@ -5305,6 +5376,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