X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf32-arm.c;h=2125582ee8a87340ac6f711e929f8776a8ad5581;hb=cf35638d431e230d51d54550e8a249e730264ea5;hp=6bd29f69c068b34da1696d3613116fa5ad4a64f8;hpb=b43420e6cdbc2b1ae000f4671470d208ac7241a9;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c index 6bd29f69c0..2125582ee8 100644 --- a/bfd/elf32-arm.c +++ b/bfd/elf32-arm.c @@ -1829,7 +1829,7 @@ elf32_arm_nabi_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); /* pr_pid */ - elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24); + elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 24); /* pr_reg */ offset = 72; @@ -2409,9 +2409,10 @@ struct a8_erratum_fix { struct a8_erratum_reloc { bfd_vma from; bfd_vma destination; + struct elf32_arm_link_hash_entry *hash; + const char *sym_name; unsigned int r_type; unsigned char st_type; - const char *sym_name; bfd_boolean non_a8_stub; }; @@ -2985,6 +2986,9 @@ using_thumb_only (struct elf32_arm_link_hash_table *globals) Tag_CPU_arch); int profile; + if (arch == TAG_CPU_ARCH_V6_M || arch == TAG_CPU_ARCH_V6S_M) + return TRUE; + if (arch != TAG_CPU_ARCH_V7 && arch != TAG_CPU_ARCH_V7E_M) return FALSE; @@ -3471,6 +3475,36 @@ static bfd_reloc_status_type elf32_arm_final_link_relocate Elf_Internal_Rela *, bfd_vma, struct bfd_link_info *, asection *, const char *, int, struct elf_link_hash_entry *, bfd_boolean *, char **); +static unsigned int +arm_stub_required_alignment (enum elf32_arm_stub_type stub_type) +{ + switch (stub_type) + { + case arm_stub_a8_veneer_b_cond: + case arm_stub_a8_veneer_b: + case arm_stub_a8_veneer_bl: + return 2; + + case arm_stub_long_branch_any_any: + case arm_stub_long_branch_v4t_arm_thumb: + case arm_stub_long_branch_thumb_only: + case arm_stub_long_branch_v4t_thumb_thumb: + case arm_stub_long_branch_v4t_thumb_arm: + case arm_stub_short_branch_v4t_thumb_arm: + case arm_stub_long_branch_any_arm_pic: + case arm_stub_long_branch_any_thumb_pic: + case arm_stub_long_branch_v4t_thumb_thumb_pic: + case arm_stub_long_branch_v4t_arm_thumb_pic: + case arm_stub_long_branch_v4t_thumb_arm_pic: + case arm_stub_long_branch_thumb_only_pic: + case arm_stub_a8_veneer_blx: + return 4; + + default: + abort (); /* Should be unreachable. */ + } +} + static bfd_boolean arm_build_one_stub (struct bfd_hash_entry *gen_entry, void * in_arg) @@ -3481,7 +3515,6 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, struct bfd_link_info *info; asection *stub_sec; bfd *stub_bfd; - bfd_vma stub_addr; bfd_byte *loc; bfd_vma sym_value; int template_size; @@ -3503,9 +3536,8 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, stub_sec = stub_entry->stub_sec; if ((globals->fix_cortex_a8 < 0) - != (stub_entry->stub_type >= arm_stub_a8_veneer_lwm)) - /* We have to do the a8 fixes last, as they are less aligned than - the other veneers. */ + != (arm_stub_required_alignment (stub_entry->stub_type) == 2)) + /* We have to do less-strictly-aligned fixes last. */ return TRUE; /* Make a note of the offset within the stubs for this entry. */ @@ -3514,10 +3546,6 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, stub_bfd = stub_sec->owner; - /* This is the address of the start of the stub. */ - stub_addr = stub_sec->output_section->vma + stub_sec->output_offset - + stub_entry->stub_offset; - /* This is the address of the stub destination. */ sym_value = (stub_entry->target_value + stub_entry->target_section->output_offset @@ -3715,16 +3743,14 @@ find_stub_size_and_template (enum elf32_arm_stub_type stub_type, static bfd_boolean arm_size_one_stub (struct bfd_hash_entry *gen_entry, - void * in_arg) + void *in_arg ATTRIBUTE_UNUSED) { struct elf32_arm_stub_hash_entry *stub_entry; - struct elf32_arm_link_hash_table *htab; const insn_sequence *template_sequence; int template_size, size; /* Massage our args to the form they really have. */ stub_entry = (struct elf32_arm_stub_hash_entry *) gen_entry; - htab = (struct elf32_arm_link_hash_table *) in_arg; BFD_ASSERT((stub_entry->stub_type > arm_stub_none) && stub_entry->stub_type < ARRAY_SIZE(stub_definitions)); @@ -4098,6 +4124,7 @@ cortex_a8_erratum_scan (bfd *input_bfd, { char *error_message = NULL; struct elf_link_hash_entry *entry; + bfd_boolean use_plt = FALSE; /* We don't care about the error returned from this function, only if there is glue or not. */ @@ -4107,12 +4134,18 @@ cortex_a8_erratum_scan (bfd *input_bfd, if (entry) found->non_a8_stub = TRUE; - if (found->r_type == R_ARM_THM_CALL - && found->st_type != STT_ARM_TFUNC) - force_target_arm = TRUE; - else if (found->r_type == R_ARM_THM_CALL - && found->st_type == STT_ARM_TFUNC) - force_target_thumb = TRUE; + /* Keep a simpler condition, for the sake of clarity. */ + if (htab->splt != NULL && found->hash != NULL + && found->hash->root.plt.offset != (bfd_vma) -1) + use_plt = TRUE; + + if (found->r_type == R_ARM_THM_CALL) + { + if (found->st_type != STT_ARM_TFUNC || use_plt) + force_target_arm = TRUE; + else + force_target_thumb = TRUE; + } } /* Check if we have an offending branch instruction. */ @@ -4679,6 +4712,7 @@ elf32_arm_size_stubs (bfd *output_bfd, a8_relocs[num_a8_relocs].st_type = st_type; a8_relocs[num_a8_relocs].sym_name = sym_name; a8_relocs[num_a8_relocs].non_a8_stub = created_stub; + a8_relocs[num_a8_relocs].hash = hash; num_a8_relocs++; } @@ -5232,7 +5266,6 @@ record_vfp11_erratum_veneer (struct bfd_link_info *link_info, struct bfd_link_hash_entry *bh; bfd_vma val; struct _arm_elf_section_data *sec_data; - int errcount; elf32_vfp11_erratum_list *newerr; hash_table = elf32_arm_hash_table (link_info); @@ -5270,7 +5303,7 @@ record_vfp11_erratum_veneer (struct bfd_link_info *link_info, myh->forced_local = 1; /* Link veneer back to calling location. */ - errcount = ++(sec_data->erratumcount); + sec_data->erratumcount += 1; newerr = (elf32_vfp11_erratum_list *) bfd_zmalloc (sizeof (elf32_vfp11_erratum_list)); @@ -6126,9 +6159,8 @@ bfd_elf32_arm_vfp11_erratum_scan (bfd *abfd, struct bfd_link_info *link_info) { elf32_vfp11_erratum_list *newerr =(elf32_vfp11_erratum_list *) bfd_zmalloc (sizeof (elf32_vfp11_erratum_list)); - int errcount; - errcount = ++(elf32_arm_section_data (sec)->erratumcount); + elf32_arm_section_data (sec)->erratumcount += 1; newerr->u.b.vfp_insn = veneer_of_insn; @@ -6840,8 +6872,6 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, unsigned long r_symndx; bfd_byte * hit_data = contents + rel->r_offset; bfd * dynobj = NULL; - Elf_Internal_Shdr * symtab_hdr; - struct elf_link_hash_entry ** sym_hashes; bfd_vma * local_got_offsets; asection * sgot = NULL; asection * splt = NULL; @@ -6880,8 +6910,6 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, sgot = bfd_get_section_by_name (dynobj, ".got"); splt = bfd_get_section_by_name (dynobj, ".plt"); } - symtab_hdr = & elf_symtab_hdr (input_bfd); - sym_hashes = elf_sym_hashes (input_bfd); local_got_offsets = elf_local_got_offsets (input_bfd); r_symndx = ELF32_R_SYM (rel->r_info); @@ -9035,7 +9063,7 @@ elf32_arm_relocate_section (bfd * output_bfd, name = bfd_section_name (input_bfd, sec); } - if (r_symndx != 0 + if (r_symndx != STN_UNDEF && r_type != R_ARM_NONE && (h == NULL || h->root.type == bfd_link_hash_defined @@ -9212,6 +9240,8 @@ insert_cantunwind_after(asection *text_sec, asection *exidx_sec) 2. Duplicate entries are merged together (EXIDX_CANTUNWIND, or unwind codes which have been inlined into the index). + If MERGE_EXIDX_ENTRIES is false, duplicate entries are not merged. + The edits are applied when the tables are written (in elf32_arm_write_section). */ @@ -9219,7 +9249,8 @@ insert_cantunwind_after(asection *text_sec, asection *exidx_sec) bfd_boolean elf32_arm_fix_exidx_coverage (asection **text_section_order, unsigned int num_text_sections, - struct bfd_link_info *info) + struct bfd_link_info *info, + bfd_boolean merge_exidx_entries) { bfd *inp; unsigned int last_second_word = 0, i; @@ -9331,7 +9362,8 @@ elf32_arm_fix_exidx_coverage (asection **text_section_order, /* Inlined unwinding data. Merge if equal to previous. */ else if ((second_word & 0x80000000) != 0) { - if (last_second_word == second_word && last_unwind_type == 1) + if (merge_exidx_entries + && last_second_word == second_word && last_unwind_type == 1) elide = 1; unwind_type = 1; last_second_word = second_word; @@ -9411,16 +9443,19 @@ elf32_arm_final_link (bfd *abfd, struct bfd_link_info *info) /* Process stub sections (eg BE8 encoding, ...). */ struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info); int i; - for(i=0; itop_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; + for (i=0; itop_id; i++) + { + sec = htab->stub_group[i].stub_sec; + /* Only process it once, in its link_sec slot. */ + if (sec && i == htab->stub_group[i].link_sec->id) + { + 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. */ @@ -9608,9 +9643,9 @@ elf32_arm_obj_attrs_arg_type (int tag) static int elf32_arm_obj_attrs_order (int num) { - if (num == 4) + if (num == LEAST_KNOWN_OBJ_ATTRIBUTE) return Tag_conformance; - if (num == 5) + if (num == LEAST_KNOWN_OBJ_ATTRIBUTE + 1) return Tag_nodefaults; if ((num - 2) < Tag_nodefaults) return num - 2; @@ -9916,7 +9951,7 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd) } } - for (i = 4; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) + for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) { /* Merge this attribute with existing attributes. */ switch (i) @@ -10000,27 +10035,26 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd) case Tag_ABI_FP_exceptions: case Tag_ABI_FP_user_exceptions: case Tag_ABI_FP_number_model: - case Tag_VFP_HP_extension: + case Tag_FP_HP_extension: case Tag_CPU_unaligned_access: case Tag_T2EE_use: - case Tag_Virtualization_use: case Tag_MPextension_use: /* Use the largest value specified. */ if (in_attr[i].i > out_attr[i].i) out_attr[i].i = in_attr[i].i; break; - case Tag_ABI_align8_preserved: + case Tag_ABI_align_preserved: case Tag_ABI_PCS_RO_data: /* Use the smallest value specified. */ if (in_attr[i].i < out_attr[i].i) out_attr[i].i = in_attr[i].i; break; - case Tag_ABI_align8_needed: + case Tag_ABI_align_needed: if ((in_attr[i].i > 0 || out_attr[i].i > 0) - && (in_attr[Tag_ABI_align8_preserved].i == 0 - || out_attr[Tag_ABI_align8_preserved].i == 0)) + && (in_attr[Tag_ABI_align_preserved].i == 0 + || out_attr[Tag_ABI_align_preserved].i == 0)) { /* This error message should be enabled once all non-conformant binaries in the toolchain have had the attributes set @@ -10041,6 +10075,27 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd) out_attr[i].i = in_attr[i].i; break; + case Tag_Virtualization_use: + /* The virtualization tag effectively stores two bits of + information: the intended use of TrustZone (in bit 0), and the + intended use of Virtualization (in bit 1). */ + if (out_attr[i].i == 0) + out_attr[i].i = in_attr[i].i; + else if (in_attr[i].i != 0 + && in_attr[i].i != out_attr[i].i) + { + if (in_attr[i].i <= 3 && out_attr[i].i <= 3) + out_attr[i].i = 3; + else + { + _bfd_error_handler + (_("error: %B: unable to merge virtualization attributes " + "with %B"), + obfd, ibfd); + result = FALSE; + } + } + break; case Tag_CPU_arch_profile: if (out_attr[i].i != in_attr[i].i) @@ -10068,8 +10123,13 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd) } } break; - case Tag_VFP_arch: + case Tag_FP_arch: { + /* Tag_ABI_HardFP_use is handled along with Tag_FP_arch since + the meaning of Tag_ABI_HardFP_use depends on Tag_FP_arch + when it's 0. It might mean absence of FP hardware if + Tag_FP_arch is zero, otherwise it is effectively SP + DP. */ + static const struct { int ver; @@ -10088,6 +10148,40 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd) int regs; int newval; + /* If the output has no requirement about FP hardware, + follow the requirement of the input. */ + if (out_attr[i].i == 0) + { + BFD_ASSERT (out_attr[Tag_ABI_HardFP_use].i == 0); + out_attr[i].i = in_attr[i].i; + out_attr[Tag_ABI_HardFP_use].i + = in_attr[Tag_ABI_HardFP_use].i; + break; + } + /* If the input has no requirement about FP hardware, do + nothing. */ + else if (in_attr[i].i == 0) + { + BFD_ASSERT (in_attr[Tag_ABI_HardFP_use].i == 0); + break; + } + + /* Both the input and the output have nonzero Tag_FP_arch. + So Tag_ABI_HardFP_use is (SP & DP) when it's zero. */ + + /* If both the input and the output have zero Tag_ABI_HardFP_use, + do nothing. */ + if (in_attr[Tag_ABI_HardFP_use].i == 0 + && out_attr[Tag_ABI_HardFP_use].i == 0) + ; + /* If the input and the output have different Tag_ABI_HardFP_use, + the combination of them is 3 (SP & DP). */ + else if (in_attr[Tag_ABI_HardFP_use].i + != out_attr[Tag_ABI_HardFP_use].i) + out_attr[Tag_ABI_HardFP_use].i = 3; + + /* Now we can handle Tag_FP_arch. */ + /* Values greater than 6 aren't defined, so just pick the biggest */ if (in_attr[i].i > 6 && in_attr[i].i > out_attr[i].i) @@ -10208,12 +10302,7 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd) /* Merged in target-independent code. */ break; case Tag_ABI_HardFP_use: - /* 1 (SP) and 2 (DP) conflict, so combine to 3 (SP & DP). */ - if ((in_attr[i].i == 1 && out_attr[i].i == 2) - || (in_attr[i].i == 2 && out_attr[i].i == 1)) - out_attr[i].i = 3; - else if (in_attr[i].i > out_attr[i].i) - out_attr[i].i = in_attr[i].i; + /* This is handled along with Tag_FP_arch. */ break; case Tag_ABI_FP_16bit_format: if (in_attr[i].i != 0 && out_attr[i].i != 0) @@ -10768,7 +10857,6 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, const Elf_Internal_Rela *rel_end; bfd *dynobj; asection *sreloc; - bfd_vma *local_got_offsets; struct elf32_arm_link_hash_table *htab; bfd_boolean needs_plt; unsigned long nsyms; @@ -10794,8 +10882,6 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, } dynobj = elf_hash_table (info)->dynobj; - local_got_offsets = elf_local_got_offsets (abfd); - symtab_hdr = & elf_symtab_hdr (abfd); sym_hashes = elf_sym_hashes (abfd); nsyms = NUM_SHDR_ENTRIES (symtab_hdr); @@ -10816,7 +10902,7 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, /* PR 9934: It is possible to have relocations that do not refer to symbols, thus it is also possible to have an object file containing relocations but no symbol table. */ - && (r_symndx > 0 || nsyms > 0)) + && (r_symndx > STN_UNDEF || nsyms > 0)) { (*_bfd_error_handler) (_("%B: bad symbol index: %d"), abfd, r_symndx); @@ -12787,108 +12873,15 @@ elf32_arm_section_from_shdr (bfd *abfd, return TRUE; } -/* A structure used to record a list of sections, independently - of the next and prev fields in the asection structure. */ -typedef struct section_list -{ - asection * sec; - struct section_list * next; - struct section_list * prev; -} -section_list; - -/* Unfortunately we need to keep a list of sections for which - an _arm_elf_section_data structure has been allocated. This - is because it is possible for functions like elf32_arm_write_section - to be called on a section which has had an elf_data_structure - allocated for it (and so the used_by_bfd field is valid) but - for which the ARM extended version of this structure - the - _arm_elf_section_data structure - has not been allocated. */ -static section_list * sections_with_arm_elf_section_data = NULL; - -static void -record_section_with_arm_elf_section_data (asection * sec) -{ - struct section_list * entry; - - entry = (struct section_list *) bfd_malloc (sizeof (* entry)); - if (entry == NULL) - return; - entry->sec = sec; - entry->next = sections_with_arm_elf_section_data; - entry->prev = NULL; - if (entry->next != NULL) - entry->next->prev = entry; - sections_with_arm_elf_section_data = entry; -} - -static struct section_list * -find_arm_elf_section_entry (asection * sec) -{ - struct section_list * entry; - static struct section_list * last_entry = NULL; - - /* This is a short cut for the typical case where the sections are added - to the sections_with_arm_elf_section_data list in forward order and - then looked up here in backwards order. This makes a real difference - to the ld-srec/sec64k.exp linker test. */ - entry = sections_with_arm_elf_section_data; - if (last_entry != NULL) - { - if (last_entry->sec == sec) - entry = last_entry; - else if (last_entry->next != NULL - && last_entry->next->sec == sec) - entry = last_entry->next; - } - - for (; entry; entry = entry->next) - if (entry->sec == sec) - break; - - if (entry) - /* Record the entry prior to this one - it is the entry we are most - likely to want to locate next time. Also this way if we have been - called from unrecord_section_with_arm_elf_section_data() we will not - be caching a pointer that is about to be freed. */ - last_entry = entry->prev; - - return entry; -} - static _arm_elf_section_data * get_arm_elf_section_data (asection * sec) { - struct section_list * entry; - - entry = find_arm_elf_section_entry (sec); - - if (entry) - return elf32_arm_section_data (entry->sec); + if (sec && sec->owner && is_arm_elf (sec->owner)) + return elf32_arm_section_data (sec); else return NULL; } -static void -unrecord_section_with_arm_elf_section_data (asection * sec) -{ - struct section_list * entry; - - entry = find_arm_elf_section_entry (sec); - - if (entry) - { - if (entry->prev != NULL) - entry->prev->next = entry->next; - if (entry->next != NULL) - entry->next->prev = entry->prev; - if (entry == sections_with_arm_elf_section_data) - sections_with_arm_elf_section_data = entry->next; - free (entry); - } -} - - typedef struct { void *finfo; @@ -13031,7 +13024,6 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry, void * in_arg) { struct elf32_arm_stub_hash_entry *stub_entry; - struct bfd_link_info *info; asection *stub_sec; bfd_vma addr; char *stub_name; @@ -13046,8 +13038,6 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry, stub_entry = (struct elf32_arm_stub_hash_entry *) gen_entry; osi = (output_arch_syminfo *) in_arg; - info = osi->info; - stub_sec = stub_entry->stub_sec; /* Ensure this stub is attached to the current section being @@ -13313,8 +13303,6 @@ elf32_arm_new_section_hook (bfd *abfd, asection *sec) sec->used_by_bfd = sdata; } - record_section_with_arm_elf_section_data (sec); - return _bfd_elf_new_section_hook (abfd, sec); } @@ -13400,7 +13388,7 @@ make_branch_to_a8_stub (struct bfd_hash_entry *gen_entry, data = (struct a8_branch_to_stub_data *) in_arg; if (stub_entry->target_section != data->writing_section - || stub_entry->stub_type < arm_stub_a8_veneer_b_cond) + || stub_entry->stub_type < arm_stub_a8_veneer_lwm) return TRUE; contents = data->contents; @@ -13745,44 +13733,13 @@ elf32_arm_write_section (bfd *output_bfd, } free (map); - arm_data->mapcount = 0; + arm_data->mapcount = -1; arm_data->mapsize = 0; arm_data->map = NULL; - unrecord_section_with_arm_elf_section_data (sec); return FALSE; } -static void -unrecord_section_via_map_over_sections (bfd * abfd ATTRIBUTE_UNUSED, - asection * sec, - void * ignore ATTRIBUTE_UNUSED) -{ - unrecord_section_with_arm_elf_section_data (sec); -} - -static bfd_boolean -elf32_arm_close_and_cleanup (bfd * abfd) -{ - if (abfd->sections) - bfd_map_over_sections (abfd, - unrecord_section_via_map_over_sections, - NULL); - - return _bfd_elf_close_and_cleanup (abfd); -} - -static bfd_boolean -elf32_arm_bfd_free_cached_info (bfd * abfd) -{ - if (abfd->sections) - bfd_map_over_sections (abfd, - unrecord_section_via_map_over_sections, - NULL); - - return _bfd_free_cached_info (abfd); -} - /* Display STT_ARM_TFUNC symbols as functions. */ static void @@ -13946,6 +13903,7 @@ const struct elf_size_info elf32_arm_size_info = }; #define ELF_ARCH bfd_arch_arm +#define ELF_TARGET_ID ARM_ELF_DATA #define ELF_MACHINE_CODE EM_ARM #ifdef __QNXTARGET__ #define ELF_MAXPAGESIZE 0x1000 @@ -13969,8 +13927,6 @@ const struct elf_size_info elf32_arm_size_info = #define bfd_elf32_find_inliner_info elf32_arm_find_inliner_info #define bfd_elf32_new_section_hook elf32_arm_new_section_hook #define bfd_elf32_bfd_is_target_special_symbol elf32_arm_is_target_special_symbol -#define bfd_elf32_close_and_cleanup elf32_arm_close_and_cleanup -#define bfd_elf32_bfd_free_cached_info elf32_arm_bfd_free_cached_info #define bfd_elf32_bfd_final_link elf32_arm_final_link #define elf_backend_get_symbol_type elf32_arm_get_symbol_type