diff options
author | Christophe Lyon <christophe.lyon@st.com> | 2010-03-02 08:19:54 +0000 |
---|---|---|
committer | Christophe Lyon <christophe.lyon@st.com> | 2010-03-02 08:19:54 +0000 |
commit | fe33d2fa468504c7c7790f1247e280aae9cd930d (patch) | |
tree | d68f2713713e4ba6d5d8b111bfa0b8fe3660a893 /bfd/elf32-arm.c | |
parent | 679b7c76e55b841830aee0642a343f14ebf0827e (diff) | |
download | gdb-fe33d2fa468504c7c7790f1247e280aae9cd930d.zip gdb-fe33d2fa468504c7c7790f1247e280aae9cd930d.tar.gz gdb-fe33d2fa468504c7c7790f1247e280aae9cd930d.tar.bz2 |
2010-03-02 Christophe Lyon <christophe.lyon@st.com>
Alan Modra <amodra@gmail.com>
bfd/
* elf32-arm.c (a8_erratum_fix): Add st_type field to record the
destination mode of the a8 stub.
(elf32_arm_link_hash_table): Add top_id field.
(elf32_arm_link_hash_table_create): Initialize top_id.
(arm_type_of_stub): Update prototype, st_type can now be updated
by this function. Actual destination address in case of PLT is
computed here, to help factorizing code.
(elf32_arm_stub_name): Update prototype, use stub_type additional
parameter to build stub name.
(elf32_arm_get_stub_entry): Update prototype, use stub_type
additional parameter to build stub entry.
(arm_build_one_stub): Use bfd_put_16/bfd_put_32 instead of
put_thumb_insn/put_arm_insn as BE8 encoding is now handled later.
Call elf32_arm_final_link_relocate to process all in-stub
relocations.
(elf32_arm_setup_section_lists): Update top_id.
(cortex_a8_erratum_scan): Record stub destination mode.
(elf32_arm_size_stubs): Update call to arm_type_of_stub according
to new prototype.
(elf32_arm_final_link_relocate): Enable processing of in-stub
REL32 relocations. Rely on arm_type_of_stub to detect if a stub is
needed, enabling code factorization.
(elf32_arm_final_link): Process stub sections.
(elf32_arm_output_map_sym): Add entry to code/data map.
ld/testsuite/
* ld-arm/arm-elf.exp: Change .text start address for
farcall-thumb-arm tests. Add v4t variant for farcall-mixed-lib
test.
* ld-arm/farcall-mixed-lib-v4t.d: New test.
* ld-arm/farcall-mixed-lib1.s: Don't force armv5t.
* ld-arm/farcall-mixed-lib2.s: Likewise.
* ld-arm/arm-call.d: Update expected results.
* ld-arm/cortex-a8-far.d: Likewise.
* ld-arm/farcall-group-size2.d: Likewise.
* ld-arm/farcall-group.d: Likewise.
* ld-arm/farcall-mix.d: Likewise.
* ld-arm/farcall-mix2.d: Likewise.
* ld-arm/farcall-mixed-app-v5.d: Likewise.
* ld-arm/farcall-mixed-app.d: Likewise.
* ld-arm/farcall-mixed-lib.d: Likewise.
* ld-arm/farcall-thumb-arm.d: Likewise.
* ld-arm/farcall-thumb-arm-blx.d: Likewise.
* ld-arm/farcall-thumb-arm-pic-veneer.d: Likewise.
* ld-arm/farcall-thumb-arm-blx-pic-veneer.d: Likewise.
* ld-arm/farcall-thumb-arm.s: Update test. Add a new call to
potentially generate different types of stubs.
Diffstat (limited to 'bfd/elf32-arm.c')
-rw-r--r-- | bfd/elf32-arm.c | 271 |
1 files changed, 164 insertions, 107 deletions
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c index a0694c1..fd40315 100644 --- a/bfd/elf32-arm.c +++ b/bfd/elf32-arm.c @@ -2399,6 +2399,7 @@ struct a8_erratum_fix { unsigned long orig_insn; char *stub_name; enum elf32_arm_stub_type stub_type; + int st_type; }; /* A table of relocs applied to branches which might trigger Cortex-A8 @@ -2650,6 +2651,9 @@ struct elf32_arm_link_hash_table information on stub grouping. */ struct map_stub *stub_group; + /* Number of elements in stub_group. */ + int top_id; + /* Assorted information used by elf32_arm_size_stubs. */ unsigned int bfd_count; int top_index; @@ -2944,6 +2948,7 @@ elf32_arm_link_hash_table_create (bfd *abfd) ret->add_stub_section = NULL; ret->layout_sections_again = NULL; ret->stub_group = NULL; + ret->top_id = 0; ret->bfd_count = 0; ret->top_index = 0; ret->input_list = NULL; @@ -3046,7 +3051,7 @@ static enum elf32_arm_stub_type arm_type_of_stub (struct bfd_link_info *info, asection *input_sec, const Elf_Internal_Rela *rel, - unsigned char st_type, + int *actual_st_type, struct elf32_arm_link_hash_entry *hash, bfd_vma destination, asection *sym_sec, @@ -3061,6 +3066,7 @@ arm_type_of_stub (struct bfd_link_info *info, int thumb_only; enum elf32_arm_stub_type stub_type = arm_stub_none; int use_plt = 0; + int st_type = *actual_st_type; /* We don't know the actual type of destination in case it is of type STT_SECTION: give up. */ @@ -3080,14 +3086,15 @@ arm_type_of_stub (struct bfd_link_info *info, + input_sec->output_section->vma + rel->r_offset); - branch_offset = (bfd_signed_vma)(destination - location); - r_type = ELF32_R_TYPE (rel->r_info); /* Keep a simpler condition, for the sake of clarity. */ - if (globals->splt != NULL && hash != NULL && hash->root.plt.offset != (bfd_vma) -1) + if (globals->splt != NULL + && hash != NULL + && hash->root.plt.offset != (bfd_vma) -1) { use_plt = 1; + /* Note when dealing with PLT entries: the main PLT stub is in ARM mode, so if the branch is in Thumb mode, another Thumb->ARM stub will be inserted later just before the ARM @@ -3096,8 +3103,15 @@ arm_type_of_stub (struct bfd_link_info *info, Thumb->Arm one and branch directly to the ARM PLT entry because it avoids spreading offset corrections in several places. */ + + destination = (globals->splt->output_section->vma + + globals->splt->output_offset + + hash->root.plt.offset); + st_type = STT_FUNC; } + branch_offset = (bfd_signed_vma)(destination - location); + if (r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_JUMP24) { /* Handle cases where: @@ -3191,7 +3205,9 @@ arm_type_of_stub (struct bfd_link_info *info, } } } - else if (r_type == R_ARM_CALL || r_type == R_ARM_JUMP24 || r_type == R_ARM_PLT32) + else if (r_type == R_ARM_CALL + || r_type == R_ARM_JUMP24 + || r_type == R_ARM_PLT32) { if (st_type == STT_ARM_TFUNC) { @@ -3246,6 +3262,12 @@ arm_type_of_stub (struct bfd_link_info *info, } } + /* If a stub is needed, record the actual destination type. */ + if (stub_type != arm_stub_none) + { + *actual_st_type = st_type; + } + return stub_type; } @@ -3255,31 +3277,34 @@ static char * elf32_arm_stub_name (const asection *input_section, const asection *sym_sec, const struct elf32_arm_link_hash_entry *hash, - const Elf_Internal_Rela *rel) + const Elf_Internal_Rela *rel, + enum elf32_arm_stub_type stub_type) { char *stub_name; bfd_size_type len; if (hash) { - len = 8 + 1 + strlen (hash->root.root.root.string) + 1 + 8 + 1; + len = 8 + 1 + strlen (hash->root.root.root.string) + 1 + 8 + 1 + 2 + 1; stub_name = (char *) bfd_malloc (len); if (stub_name != NULL) - sprintf (stub_name, "%08x_%s+%x", + sprintf (stub_name, "%08x_%s+%x_%d", input_section->id & 0xffffffff, hash->root.root.root.string, - (int) rel->r_addend & 0xffffffff); + (int) rel->r_addend & 0xffffffff, + (int) stub_type); } else { - len = 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1; + len = 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1 + 2 + 1; stub_name = (char *) bfd_malloc (len); if (stub_name != NULL) - sprintf (stub_name, "%08x_%x:%x+%x", + sprintf (stub_name, "%08x_%x:%x+%x_%d", input_section->id & 0xffffffff, sym_sec->id & 0xffffffff, (int) ELF32_R_SYM (rel->r_info) & 0xffffffff, - (int) rel->r_addend & 0xffffffff); + (int) rel->r_addend & 0xffffffff, + (int) stub_type); } return stub_name; @@ -3293,7 +3318,8 @@ elf32_arm_get_stub_entry (const asection *input_section, const asection *sym_sec, struct elf_link_hash_entry *hash, const Elf_Internal_Rela *rel, - struct elf32_arm_link_hash_table *htab) + struct elf32_arm_link_hash_table *htab, + enum elf32_arm_stub_type stub_type) { struct elf32_arm_stub_hash_entry *stub_entry; struct elf32_arm_link_hash_entry *h = (struct elf32_arm_link_hash_entry *) hash; @@ -3311,7 +3337,8 @@ elf32_arm_get_stub_entry (const asection *input_section, if (h != NULL && h->stub_cache != NULL && h->stub_cache->h == h - && h->stub_cache->id_sec == id_sec) + && h->stub_cache->id_sec == id_sec + && h->stub_cache->stub_type == stub_type) { stub_entry = h->stub_cache; } @@ -3319,7 +3346,7 @@ elf32_arm_get_stub_entry (const asection *input_section, { char *stub_name; - stub_name = elf32_arm_stub_name (id_sec, sym_sec, h, rel); + stub_name = elf32_arm_stub_name (id_sec, sym_sec, h, rel, stub_type); if (stub_name == NULL) return NULL; @@ -3479,7 +3506,7 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, /* We have to do the a8 fixes last, as they are less aligned than the other veneers. */ return TRUE; - + /* Make a note of the offset within the stubs for this entry. */ stub_entry->stub_offset = stub_sec->size; loc = stub_sec->contents + stub_entry->stub_offset; @@ -3514,17 +3541,17 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, BFD_ASSERT ((data & 0xff00) == 0xd000); data |= ((stub_entry->orig_insn >> 22) & 0xf) << 8; } - put_thumb_insn (globals, stub_bfd, data, loc + size); + bfd_put_16 (stub_bfd, data, loc + size); size += 2; } break; case THUMB32_TYPE: - put_thumb_insn (globals, stub_bfd, - (template_sequence[i].data >> 16) & 0xffff, - loc + size); - put_thumb_insn (globals, stub_bfd, template_sequence[i].data & 0xffff, - loc + size + 2); + bfd_put_16 (stub_bfd, + (template_sequence[i].data >> 16) & 0xffff, + loc + size); + bfd_put_16 (stub_bfd, template_sequence[i].data & 0xffff, + loc + size + 2); if (template_sequence[i].r_type != R_ARM_NONE) { stub_reloc_idx[nrelocs] = i; @@ -3534,8 +3561,8 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, break; case ARM_TYPE: - put_arm_insn (globals, stub_bfd, template_sequence[i].data, - loc + size); + bfd_put_32 (stub_bfd, template_sequence[i].data, + loc + size); /* Handle cases where the target is encoded within the instruction. */ if (template_sequence[i].r_type == R_ARM_JUMP24) @@ -3614,11 +3641,23 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, } else { - _bfd_final_link_relocate (elf32_arm_howto_from_type - (template_sequence[stub_reloc_idx[i]].r_type), stub_bfd, stub_sec, - stub_sec->contents, stub_entry->stub_offset + stub_reloc_offset[i], - sym_value + stub_entry->target_addend, - template_sequence[stub_reloc_idx[i]].reloc_addend); + Elf_Internal_Rela rel; + bfd_boolean unresolved_reloc; + char *error_message; + bfd_vma points_to = sym_value + stub_entry->target_addend + + template_sequence[stub_reloc_idx[i]].reloc_addend; + + rel.r_offset = stub_entry->stub_offset + stub_reloc_offset[i]; + rel.r_info = ELF32_R_INFO (0, + template_sequence[stub_reloc_idx[i]].r_type); + rel.r_addend = 0; + + elf32_arm_final_link_relocate (elf32_arm_howto_from_type + (template_sequence[stub_reloc_idx[i]].r_type), + stub_bfd, info->output_bfd, stub_sec, stub_sec->contents, &rel, + points_to, info, stub_entry->target_section, "", stub_entry->st_type, + (struct elf_link_hash_entry *) stub_entry->h, &unresolved_reloc, + &error_message); } return TRUE; @@ -3745,6 +3784,7 @@ elf32_arm_setup_section_lists (bfd *output_bfd, htab->stub_group = (struct map_stub *) bfd_zmalloc (amt); if (htab->stub_group == NULL) return -1; + htab->top_id = top_id; /* We can't use output_bfd->section_count here to find the top output section index as some sections may have been removed, and @@ -4033,7 +4073,7 @@ cortex_a8_erratum_scan (bfd *input_bfd, } is_32bit_branch = is_b || is_bl || is_blx || is_bcc; - + if (((base_vma + i) & 0xfff) == 0xffe && insn_32bit && is_32bit_branch @@ -4204,6 +4244,8 @@ cortex_a8_erratum_scan (bfd *input_bfd, a8_fixes[num_a8_fixes].orig_insn = insn; a8_fixes[num_a8_fixes].stub_name = stub_name; a8_fixes[num_a8_fixes].stub_type = stub_type; + a8_fixes[num_a8_fixes].st_type = + is_blx ? STT_FUNC : STT_ARM_TFUNC; num_a8_fixes++; } @@ -4219,11 +4261,11 @@ cortex_a8_erratum_scan (bfd *input_bfd, if (elf_section_data (section)->this_hdr.contents == NULL) free (contents); } - + *a8_fixes_p = a8_fixes; *num_a8_fixes_p = num_a8_fixes; *a8_fix_table_size_p = a8_fix_table_size; - + return FALSE; } @@ -4374,7 +4416,7 @@ elf32_arm_size_stubs (bfd *output_bfd, const char *sym_name; char *stub_name; const asection *id_sec; - unsigned char st_type; + int st_type; bfd_boolean created_stub = FALSE; r_type = ELF32_R_TYPE (irela->r_info); @@ -4432,7 +4474,7 @@ elf32_arm_size_stubs (bfd *output_bfd, /* This is an undefined symbol. It can never be resolved. */ continue; - + if (ELF_ST_TYPE (sym->st_info) != STT_SECTION) sym_value = sym->st_value; destination = (sym_value + irela->r_addend @@ -4526,7 +4568,7 @@ elf32_arm_size_stubs (bfd *output_bfd, { /* Determine what (if any) linker stub is needed. */ stub_type = arm_type_of_stub (info, section, irela, - st_type, hash, + &st_type, hash, destination, sym_sec, input_bfd, sym_name); if (stub_type == arm_stub_none) @@ -4537,7 +4579,7 @@ elf32_arm_size_stubs (bfd *output_bfd, /* Get the name of this stub. */ stub_name = elf32_arm_stub_name (id_sec, sym_sec, hash, - irela); + irela, stub_type); if (!stub_name) goto error_ret_free_internal; @@ -4737,7 +4779,7 @@ elf32_arm_size_stubs (bfd *output_bfd, stub_entry->target_value = a8_fixes[i].offset; stub_entry->target_addend = a8_fixes[i].addend; stub_entry->orig_insn = a8_fixes[i].orig_insn; - stub_entry->st_type = STT_ARM_TFUNC; + stub_entry->st_type = a8_fixes[i].st_type; size = find_stub_size_and_template (a8_fixes[i].stub_type, &template_sequence, @@ -6918,6 +6960,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, ".tls_vars") == 0) && ((r_type != R_ARM_REL32 && r_type != R_ARM_REL32_NOI) || !SYMBOL_CALLS_LOCAL (info, h)) + && (!strstr (input_section->name, STUB_SUFFIX)) && (h == NULL || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT || h->root.type != bfd_link_hash_undefweak) @@ -7042,7 +7085,6 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, case R_ARM_PC24: /* Arm B/BL instruction. */ case R_ARM_PLT32: { - bfd_signed_vma branch_offset; struct elf32_arm_stub_hash_entry *stub_entry = NULL; if (r_type == R_ARM_XPC25) @@ -7078,45 +7120,46 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, || r_type == R_ARM_JUMP24 || r_type == R_ARM_PLT32) { - bfd_vma from; - - /* If the call goes through a PLT entry, make sure to - check distance to the right destination address. */ - if (h != NULL && splt != NULL && h->plt.offset != (bfd_vma) -1) - { - value = (splt->output_section->vma - + splt->output_offset - + h->plt.offset); - *unresolved_reloc_p = FALSE; - /* The PLT entry is in ARM mode, regardless of the - target function. */ - sym_flags = STT_FUNC; - } + enum elf32_arm_stub_type stub_type = arm_stub_none; + struct elf32_arm_link_hash_entry *hash; + + hash = (struct elf32_arm_link_hash_entry *) h; + stub_type = arm_type_of_stub (info, input_section, rel, + &sym_flags, hash, + value, sym_sec, + input_bfd, sym_name); - from = (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); - branch_offset = (bfd_signed_vma)(value - from); - - if (branch_offset > ARM_MAX_FWD_BRANCH_OFFSET - || branch_offset < ARM_MAX_BWD_BRANCH_OFFSET - || ((sym_flags == STT_ARM_TFUNC) - && (((r_type == R_ARM_CALL) && !globals->use_blx) - || (r_type == R_ARM_JUMP24) - || (r_type == R_ARM_PLT32) )) - ) + if (stub_type != arm_stub_none) { /* The target is out of reach, so redirect the branch to the local stub for this function. */ stub_entry = elf32_arm_get_stub_entry (input_section, sym_sec, h, - rel, globals); + rel, globals, + stub_type); if (stub_entry != NULL) value = (stub_entry->stub_offset + stub_entry->stub_sec->output_offset + stub_entry->stub_sec->output_section->vma); } + else + { + /* If the call goes through a PLT entry, make sure to + check distance to the right destination address. */ + if (h != NULL + && splt != NULL + && h->plt.offset != (bfd_vma) -1) + { + value = (splt->output_section->vma + + splt->output_offset + + h->plt.offset); + *unresolved_reloc_p = FALSE; + /* The PLT entry is in ARM mode, regardless of the + target function. */ + sym_flags = STT_FUNC; + } + } } /* The ARM ELF ABI says that this reloc is computed as: S - P + A @@ -7501,58 +7544,29 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, } } - /* Handle calls via the PLT. */ - if (h != NULL && splt != NULL && h->plt.offset != (bfd_vma) -1) - { - value = (splt->output_section->vma - + splt->output_offset - + h->plt.offset); - if (globals->use_blx && r_type == R_ARM_THM_CALL) - { - /* If the Thumb BLX instruction is available, convert the - BL to a BLX instruction to call the ARM-mode PLT entry. */ - lower_insn = (lower_insn & ~0x1000) | 0x0800; - sym_flags = STT_FUNC; - } - else - { - /* Target the Thumb stub before the ARM PLT entry. */ - value -= PLT_THUMB_STUB_SIZE; - sym_flags = STT_ARM_TFUNC; - } - *unresolved_reloc_p = FALSE; - } - + enum elf32_arm_stub_type stub_type = arm_stub_none; if (r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_JUMP24) { /* Check if a stub has to be inserted because the destination is too far. */ - bfd_vma from; - bfd_signed_vma branch_offset; - struct elf32_arm_stub_hash_entry *stub_entry = NULL; - - from = (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); - branch_offset = (bfd_signed_vma)(value - from); - - if ((!thumb2 - && (branch_offset > THM_MAX_FWD_BRANCH_OFFSET - || (branch_offset < THM_MAX_BWD_BRANCH_OFFSET))) - || - (thumb2 - && (branch_offset > THM2_MAX_FWD_BRANCH_OFFSET - || (branch_offset < THM2_MAX_BWD_BRANCH_OFFSET))) - || ((sym_flags != STT_ARM_TFUNC) - && (((r_type == R_ARM_THM_CALL) && !globals->use_blx) - || r_type == R_ARM_THM_JUMP24))) + struct elf32_arm_stub_hash_entry *stub_entry; + struct elf32_arm_link_hash_entry *hash; + + hash = (struct elf32_arm_link_hash_entry *) h; + + stub_type = arm_type_of_stub (info, input_section, rel, + &sym_flags, hash, value, sym_sec, + input_bfd, sym_name); + + if (stub_type != arm_stub_none) { /* The target is out of reach or we are changing modes, so redirect the branch to the local stub for this function. */ stub_entry = elf32_arm_get_stub_entry (input_section, sym_sec, h, - rel, globals); + rel, globals, + stub_type); if (stub_entry != NULL) value = (stub_entry->stub_offset + stub_entry->stub_sec->output_offset @@ -7569,6 +7583,33 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, } } + /* Handle calls via the PLT. */ + if (stub_type == arm_stub_none + && h != NULL + && splt != NULL + && h->plt.offset != (bfd_vma) -1) + { + value = (splt->output_section->vma + + splt->output_offset + + h->plt.offset); + + if (globals->use_blx && r_type == R_ARM_THM_CALL) + { + /* If the Thumb BLX instruction is available, convert + the BL to a BLX instruction to call the ARM-mode + PLT entry. */ + lower_insn = (lower_insn & ~0x1000) | 0x0800; + sym_flags = STT_FUNC; + } + else + { + /* Target the Thumb stub before the ARM PLT entry. */ + value -= PLT_THUMB_STUB_SIZE; + sym_flags = STT_ARM_TFUNC; + } + *unresolved_reloc_p = FALSE; + } + relocation = value + signed_addend; relocation -= (input_section->output_section->vma @@ -9357,6 +9398,7 @@ static bfd_boolean elf32_arm_final_link (bfd *abfd, struct bfd_link_info *info) { struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (info); + asection *sec, *osec; if (globals == NULL) return FALSE; @@ -9365,6 +9407,20 @@ elf32_arm_final_link (bfd *abfd, struct bfd_link_info *info) if (!bfd_elf_final_link (abfd, info)) return FALSE; + /* Process stub sections (eg BE8 encoding, ...). */ + struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info); + int i; + for(i=0; i<htab->top_id; i++) { + sec = htab->stub_group[i].stub_sec; + if (sec) { + osec = sec->output_section; + elf32_arm_write_section (abfd, info, sec, sec->contents); + if (! bfd_set_section_contents (abfd, osec, sec->contents, + sec->output_offset, sec->size)) + return FALSE; + } + } + /* Write out any glue sections now that we have created all the stubs. */ if (globals->bfd_of_glue_owner != NULL) @@ -12866,6 +12922,7 @@ elf32_arm_output_map_sym (output_arch_syminfo *osi, sym.st_other = 0; sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_NOTYPE); sym.st_shndx = osi->sec_shndx; + elf32_arm_section_map_add (osi->sec, names[type][1], offset); return osi->func (osi->finfo, names[type], &sym, osi->sec, NULL) == 1; } |