X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Felf32-arm.c;h=b449ee8333164d08bd997360b75c0869ff29570c;hb=fc3e1e3c7e5d81ec71176b7015e1f0b5d81d751f;hp=2a2d4611ab5310c5081c8f7b4be22b8cf1364d1c;hpb=48229727d832a7181bfa8e36a77b480cd4efdf74;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c index 2a2d4611ab..b449ee8333 100644 --- a/bfd/elf32-arm.c +++ b/bfd/elf32-arm.c @@ -1,6 +1,6 @@ /* 32-bit ELF support for ARM Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, - 2008 Free Software Foundation, Inc. + 2008, 2009 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -61,8 +61,6 @@ #define ARM_ELF_ABI_VERSION 0 #define ARM_ELF_OS_ABI_VERSION ELFOSABI_ARM -static struct elf_backend_data elf32_arm_vxworks_bed; - static bfd_boolean elf32_arm_write_section (bfd *output_bfd, struct bfd_link_info *link_info, asection *sec, @@ -2228,12 +2226,14 @@ static const insn_sequence elf32_arm_stub_a8_veneer_blx[] = enum elf32_arm_stub_type { arm_stub_none, DEF_STUBS + /* Note the first a8_veneer type */ + arm_stub_a8_veneer_lwm = arm_stub_a8_veneer_b_cond }; #undef DEF_STUB typedef struct { - const insn_sequence* template; + const insn_sequence* template_sequence; int template_size; } stub_def; @@ -2521,6 +2521,17 @@ struct elf32_arm_link_hash_entry ((struct elf32_arm_stub_hash_entry *) \ bfd_hash_lookup ((table), (string), (create), (copy))) +/* Array to keep track of which stub sections have been created, and + information on stub grouping. */ +struct map_stub +{ + /* This is the section to which stubs in the group will be + attached. */ + asection *link_sec; + /* The stub section. */ + asection *stub_sec; +}; + /* ARM ELF linker hash table. */ struct elf32_arm_link_hash_table { @@ -2618,8 +2629,8 @@ struct elf32_arm_link_hash_table bfd_vma offset; } tls_ldm_got; - /* Small local sym to section mapping cache. */ - struct sym_sec_cache sym_sec; + /* Small local sym cache. */ + struct sym_cache sym_cache; /* For convenience in allocate_dynrelocs. */ bfd * obfd; @@ -2636,14 +2647,7 @@ struct elf32_arm_link_hash_table /* Array to keep track of which stub sections have been created, and information on stub grouping. */ - struct map_stub - { - /* This is the section to which stubs in the group will be - attached. */ - asection *link_sec; - /* The stub section. */ - asection *stub_sec; - } *stub_group; + struct map_stub *stub_group; /* Assorted information used by elf32_arm_size_stubs. */ unsigned int bfd_count; @@ -2664,7 +2668,8 @@ elf32_arm_link_hash_newfunc (struct bfd_hash_entry * entry, /* Allocate the structure if it has not already been allocated by a subclass. */ if (ret == NULL) - ret = bfd_hash_allocate (table, sizeof (struct elf32_arm_link_hash_entry)); + ret = (struct elf32_arm_link_hash_entry *) + bfd_hash_allocate (table, sizeof (struct elf32_arm_link_hash_entry)); if (ret == NULL) return (struct bfd_hash_entry *) ret; @@ -2698,8 +2703,8 @@ stub_hash_newfunc (struct bfd_hash_entry *entry, subclass. */ if (entry == NULL) { - entry = bfd_hash_allocate (table, - sizeof (struct elf32_arm_stub_hash_entry)); + entry = (struct bfd_hash_entry *) + bfd_hash_allocate (table, sizeof (struct elf32_arm_stub_hash_entry)); if (entry == NULL) return entry; } @@ -2716,12 +2721,15 @@ stub_hash_newfunc (struct bfd_hash_entry *entry, eh->stub_offset = 0; eh->target_value = 0; eh->target_section = NULL; + eh->target_addend = 0; + eh->orig_insn = 0; eh->stub_type = arm_stub_none; eh->stub_size = 0; eh->stub_template = NULL; eh->stub_template_size = 0; eh->h = NULL; eh->id_sec = NULL; + eh->output_name = NULL; } return entry; @@ -2748,15 +2756,9 @@ create_got_section (bfd *dynobj, struct bfd_link_info *info) if (!htab->sgot || !htab->sgotplt) abort (); - htab->srelgot = bfd_make_section_with_flags (dynobj, - RELOC_SECTION (htab, ".got"), - (SEC_ALLOC | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED - | SEC_READONLY)); - if (htab->srelgot == NULL - || ! bfd_set_section_alignment (dynobj, htab->srelgot, 2)) + htab->srelgot = bfd_get_section_by_name (dynobj, + RELOC_SECTION (htab, ".got")); + if (htab->srelgot == NULL) return FALSE; return TRUE; } @@ -2883,7 +2885,7 @@ elf32_arm_link_hash_table_create (bfd *abfd) struct elf32_arm_link_hash_table *ret; bfd_size_type amt = sizeof (struct elf32_arm_link_hash_table); - ret = bfd_malloc (amt); + ret = (struct elf32_arm_link_hash_table *) bfd_malloc (amt); if (ret == NULL) return NULL; @@ -2927,7 +2929,7 @@ elf32_arm_link_hash_table_create (bfd *abfd) ret->vxworks_p = 0; ret->symbian_p = 0; ret->use_rel = 1; - ret->sym_sec.abfd = NULL; + ret->sym_cache.abfd = NULL; ret->obfd = abfd; ret->tls_ldm_got.refcount = 0; ret->stub_bfd = NULL; @@ -2988,6 +2990,26 @@ using_thumb2 (struct elf32_arm_link_hash_table *globals) return arch == TAG_CPU_ARCH_V6T2 || arch >= TAG_CPU_ARCH_V7; } +/* Determine what kind of NOPs are available. */ + +static bfd_boolean +arch_has_arm_nop (struct elf32_arm_link_hash_table *globals) +{ + const int arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, + Tag_CPU_arch); + return arch == TAG_CPU_ARCH_V6T2 + || arch == TAG_CPU_ARCH_V6K + || arch == TAG_CPU_ARCH_V7; +} + +static bfd_boolean +arch_has_thumb2_nop (struct elf32_arm_link_hash_table *globals) +{ + const int arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, + Tag_CPU_arch); + return arch == TAG_CPU_ARCH_V6T2 || arch == TAG_CPU_ARCH_V7; +} + static bfd_boolean arm_stub_is_thumb (enum elf32_arm_stub_type stub_type) { @@ -3229,7 +3251,7 @@ elf32_arm_stub_name (const asection *input_section, if (hash) { len = 8 + 1 + strlen (hash->root.root.root.string) + 1 + 8 + 1; - stub_name = bfd_malloc (len); + stub_name = (char *) bfd_malloc (len); if (stub_name != NULL) sprintf (stub_name, "%08x_%s+%x", input_section->id & 0xffffffff, @@ -3239,7 +3261,7 @@ elf32_arm_stub_name (const asection *input_section, else { len = 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1; - stub_name = bfd_malloc (len); + stub_name = (char *) bfd_malloc (len); if (stub_name != NULL) sprintf (stub_name, "%08x_%x:%x+%x", input_section->id & 0xffffffff, @@ -3324,7 +3346,7 @@ elf32_arm_create_or_find_stub_sec (asection **link_sec_p, asection *section, namelen = strlen (link_sec->name); len = namelen + sizeof (STUB_SUFFIX); - s_name = bfd_alloc (htab->stub_bfd, len); + s_name = (char *) bfd_alloc (htab->stub_bfd, len); if (s_name == NULL) return NULL; @@ -3424,7 +3446,7 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, bfd_vma sym_value; int template_size; int size; - const insn_sequence *template; + const insn_sequence *template_sequence; int i; struct elf32_arm_link_hash_table * globals; int stub_reloc_idx[MAXRELOCS] = {-1, -1}; @@ -3440,6 +3462,12 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, htab = elf32_arm_hash_table (info); stub_sec = stub_entry->stub_sec; + if ((htab->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. */ + 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; @@ -3455,18 +3483,18 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, + stub_entry->target_section->output_offset + stub_entry->target_section->output_section->vma); - template = stub_entry->stub_template; + template_sequence = stub_entry->stub_template; template_size = stub_entry->stub_template_size; size = 0; for (i = 0; i < template_size; i++) { - switch (template[i].type) + switch (template_sequence[i].type) { case THUMB16_TYPE: { - bfd_vma data = template[i].data; - if (template[i].reloc_addend != 0) + bfd_vma data = (bfd_vma) template_sequence[i].data; + if (template_sequence[i].reloc_addend != 0) { /* We've borrowed the reloc_addend field to mean we should insert a condition code into this (Thumb-1 branch) @@ -3480,11 +3508,12 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, break; case THUMB32_TYPE: - put_thumb_insn (globals, stub_bfd, (template[i].data >> 16) & 0xffff, + put_thumb_insn (globals, stub_bfd, + (template_sequence[i].data >> 16) & 0xffff, loc + size); - put_thumb_insn (globals, stub_bfd, template[i].data & 0xffff, + put_thumb_insn (globals, stub_bfd, template_sequence[i].data & 0xffff, loc + size + 2); - if (template[i].r_type != R_ARM_NONE) + if (template_sequence[i].r_type != R_ARM_NONE) { stub_reloc_idx[nrelocs] = i; stub_reloc_offset[nrelocs++] = size; @@ -3493,10 +3522,11 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, break; case ARM_TYPE: - put_arm_insn (globals, stub_bfd, template[i].data, loc + size); + put_arm_insn (globals, stub_bfd, template_sequence[i].data, + loc + size); /* Handle cases where the target is encoded within the instruction. */ - if (template[i].r_type == R_ARM_JUMP24) + if (template_sequence[i].r_type == R_ARM_JUMP24) { stub_reloc_idx[nrelocs] = i; stub_reloc_offset[nrelocs++] = size; @@ -3505,7 +3535,7 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, break; case DATA_TYPE: - bfd_put_32 (stub_bfd, template[i].data, loc + size); + bfd_put_32 (stub_bfd, template_sequence[i].data, loc + size); stub_reloc_idx[nrelocs] = i; stub_reloc_offset[nrelocs++] = size; size += 4; @@ -3532,22 +3562,23 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, BFD_ASSERT (nrelocs != 0 && nrelocs <= MAXRELOCS); for (i = 0; i < nrelocs; i++) - if (template[stub_reloc_idx[i]].r_type == R_ARM_THM_JUMP24 - || template[stub_reloc_idx[i]].r_type == R_ARM_THM_JUMP19 - || template[stub_reloc_idx[i]].r_type == R_ARM_THM_CALL - || template[stub_reloc_idx[i]].r_type == R_ARM_THM_XPC22) + if (template_sequence[stub_reloc_idx[i]].r_type == R_ARM_THM_JUMP24 + || template_sequence[stub_reloc_idx[i]].r_type == R_ARM_THM_JUMP19 + || template_sequence[stub_reloc_idx[i]].r_type == R_ARM_THM_CALL + || template_sequence[stub_reloc_idx[i]].r_type == R_ARM_THM_XPC22) { Elf_Internal_Rela rel; bfd_boolean unresolved_reloc; char *error_message; int sym_flags - = (template[stub_reloc_idx[i]].r_type != R_ARM_THM_XPC22) + = (template_sequence[stub_reloc_idx[i]].r_type != R_ARM_THM_XPC22) ? STT_ARM_TFUNC : 0; bfd_vma points_to = sym_value + stub_entry->target_addend; rel.r_offset = stub_entry->stub_offset + stub_reloc_offset[i]; - rel.r_info = ELF32_R_INFO (0, template[stub_reloc_idx[i]].r_type); - rel.r_addend = template[stub_reloc_idx[i]].reloc_addend; + rel.r_info = ELF32_R_INFO (0, + template_sequence[stub_reloc_idx[i]].r_type); + rel.r_addend = template_sequence[stub_reloc_idx[i]].reloc_addend; if (stub_entry->stub_type == arm_stub_a8_veneer_b_cond && i == 0) /* The first relocation in the elf32_arm_stub_a8_veneer_b_cond[] @@ -3555,24 +3586,27 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, branch. */ points_to = sym_value; + /* There may be unintended consequences if this is not true. */ + BFD_ASSERT (stub_entry->h == NULL); + /* Note: _bfd_final_link_relocate doesn't handle these relocations properly. We should probably use this function unconditionally, rather than only for certain relocations listed in the enclosing conditional, for the sake of consistency. */ elf32_arm_final_link_relocate (elf32_arm_howto_from_type - (template[stub_reloc_idx[i]].r_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, "", sym_flags, - (struct elf_link_hash_entry *) stub_entry, &unresolved_reloc, + (struct elf_link_hash_entry *) stub_entry->h, &unresolved_reloc, &error_message); } else { _bfd_final_link_relocate (elf32_arm_howto_from_type - (template[stub_reloc_idx[i]].r_type), stub_bfd, stub_sec, + (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[stub_reloc_idx[i]].reloc_addend); + template_sequence[stub_reloc_idx[i]].reloc_addend); } return TRUE; @@ -3587,17 +3621,17 @@ find_stub_size_and_template (enum elf32_arm_stub_type stub_type, const insn_sequence **stub_template, int *stub_template_size) { - const insn_sequence *template = NULL; + const insn_sequence *template_sequence = NULL; int template_size = 0, i; unsigned int size; - template = stub_definitions[stub_type].template; + template_sequence = stub_definitions[stub_type].template_sequence; template_size = stub_definitions[stub_type].template_size; size = 0; for (i = 0; i < template_size; i++) { - switch (template[i].type) + switch (template_sequence[i].type) { case THUMB16_TYPE: size += 2; @@ -3616,7 +3650,7 @@ find_stub_size_and_template (enum elf32_arm_stub_type stub_type, } if (stub_template) - *stub_template = template; + *stub_template = template_sequence; if (stub_template_size) *stub_template_size = template_size; @@ -3633,7 +3667,7 @@ arm_size_one_stub (struct bfd_hash_entry *gen_entry, { struct elf32_arm_stub_hash_entry *stub_entry; struct elf32_arm_link_hash_table *htab; - const insn_sequence *template; + const insn_sequence *template_sequence; int template_size, size; /* Massage our args to the form they really have. */ @@ -3643,11 +3677,11 @@ arm_size_one_stub (struct bfd_hash_entry *gen_entry, BFD_ASSERT((stub_entry->stub_type > arm_stub_none) && stub_entry->stub_type < ARRAY_SIZE(stub_definitions)); - size = find_stub_size_and_template (stub_entry->stub_type, &template, + size = find_stub_size_and_template (stub_entry->stub_type, &template_sequence, &template_size); stub_entry->stub_size = size; - stub_entry->stub_template = template; + stub_entry->stub_template = template_sequence; stub_entry->stub_template_size = template_size; size = (size + 7) & ~7; @@ -3694,7 +3728,7 @@ elf32_arm_setup_section_lists (bfd *output_bfd, htab->bfd_count = bfd_count; amt = sizeof (struct map_stub) * (top_id + 1); - htab->stub_group = bfd_zmalloc (amt); + htab->stub_group = (struct map_stub *) bfd_zmalloc (amt); if (htab->stub_group == NULL) return -1; @@ -3711,7 +3745,7 @@ elf32_arm_setup_section_lists (bfd *output_bfd, htab->top_index = top_index; amt = sizeof (asection *) * (top_index + 1); - input_list = bfd_malloc (amt); + input_list = (asection **) bfd_malloc (amt); htab->input_list = input_list; if (input_list == NULL) return -1; @@ -3868,7 +3902,8 @@ group_sections (struct elf32_arm_link_hash_table *htab, static int a8_reloc_compare (const void *a, const void *b) { - const struct a8_erratum_reloc *ra = a, *rb = b; + const struct a8_erratum_reloc *ra = (const struct a8_erratum_reloc *) a; + const struct a8_erratum_reloc *rb = (const struct a8_erratum_reloc *) b; if (ra->from < rb->from) return -1; @@ -3883,16 +3918,19 @@ static struct elf_link_hash_entry *find_thumb_glue (struct bfd_link_info *, /* Helper function to scan code for sequences which might trigger the Cortex-A8 branch/TLB erratum. Fill in the table described by A8_FIXES_P, - NUM_A8_FIXES_P, A8_FIX_TABLE_SIZE_P. Return 1 if an error occurs, 0 + NUM_A8_FIXES_P, A8_FIX_TABLE_SIZE_P. Returns true if an error occurs, false otherwise. */ -static int -cortex_a8_erratum_scan (bfd *input_bfd, struct bfd_link_info *info, +static bfd_boolean +cortex_a8_erratum_scan (bfd *input_bfd, + struct bfd_link_info *info, struct a8_erratum_fix **a8_fixes_p, unsigned int *num_a8_fixes_p, unsigned int *a8_fix_table_size_p, struct a8_erratum_reloc *a8_relocs, - unsigned int num_a8_relocs) + unsigned int num_a8_relocs, + unsigned prev_num_a8_fixes, + bfd_boolean *stub_changed_p) { asection *section; struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info); @@ -3921,7 +3959,7 @@ cortex_a8_erratum_scan (bfd *input_bfd, struct bfd_link_info *info, if (elf_section_data (section)->this_hdr.contents != NULL) contents = elf_section_data (section)->this_hdr.contents; else if (! bfd_malloc_and_get_section (input_bfd, section, &contents)) - return 1; + return TRUE; sec_data = elf32_arm_section_data (section); @@ -3948,9 +3986,7 @@ cortex_a8_erratum_scan (bfd *input_bfd, struct bfd_link_info *info, * The branch target is in the same 4KB region as the first half of the branch. * The instruction before the branch is a 32-bit - length non-branch instruction. - */ - + length non-branch instruction. */ for (i = span_start; i < span_end;) { unsigned int insn = bfd_getl16 (&contents[i]); @@ -3978,10 +4014,13 @@ cortex_a8_erratum_scan (bfd *input_bfd, struct bfd_link_info *info, is_32bit_branch = is_b || is_bl || is_blx || is_bcc; - if (((base_vma + i) & 0xfff) == 0xffe && insn_32bit - && is_32bit_branch && last_was_32bit && !last_was_branch) + if (((base_vma + i) & 0xfff) == 0xffe + && insn_32bit + && is_32bit_branch + && last_was_32bit + && ! last_was_branch) { - bfd_vma offset; + bfd_signed_vma offset; bfd_boolean force_target_arm = FALSE; bfd_boolean force_target_thumb = FALSE; bfd_vma target; @@ -3989,9 +4028,10 @@ cortex_a8_erratum_scan (bfd *input_bfd, struct bfd_link_info *info, struct a8_erratum_reloc key, *found; key.from = base_vma + i; - found = bsearch (&key, a8_relocs, num_a8_relocs, - sizeof (struct a8_erratum_reloc), - &a8_reloc_compare); + found = (struct a8_erratum_reloc *) + bsearch (&key, a8_relocs, num_a8_relocs, + sizeof (struct a8_erratum_reloc), + &a8_reloc_compare); if (found) { @@ -4030,7 +4070,7 @@ cortex_a8_erratum_scan (bfd *input_bfd, struct bfd_link_info *info, offset |= (insn & 0x800) ? 0x80000 : 0; offset |= (insn & 0x4000000) ? 0x100000 : 0; if (offset & 0x100000) - offset |= ~0xfffff; + offset |= ~ ((bfd_signed_vma) 0xfffff); stub_type = arm_stub_a8_veneer_b_cond; } else if (is_b || is_bl || is_blx) @@ -4047,10 +4087,10 @@ cortex_a8_erratum_scan (bfd *input_bfd, struct bfd_link_info *info, offset |= i1 << 23; offset |= s << 24; if (offset & 0x1000000) - offset |= ~0xffffff; + offset |= ~ ((bfd_signed_vma) 0xffffff); if (is_blx) - offset &= ~3u; + offset &= ~ ((bfd_signed_vma) 3); stub_type = is_blx ? arm_stub_a8_veneer_blx : is_bl ? arm_stub_a8_veneer_bl : arm_stub_a8_veneer_b; @@ -4083,14 +4123,15 @@ cortex_a8_erratum_scan (bfd *input_bfd, struct bfd_link_info *info, } if (is_blx) - pc_for_insn &= ~3u; + pc_for_insn &= ~ ((bfd_vma) 3); /* If we found a relocation, use the proper destination, not the offset in the (unrelocated) instruction. Note this is always done if we switched the stub type above. */ if (found) - offset = found->destination - pc_for_insn; + offset = + (bfd_signed_vma) (found->destination - pc_for_insn); target = pc_for_insn + offset; @@ -4102,19 +4143,39 @@ cortex_a8_erratum_scan (bfd *input_bfd, struct bfd_link_info *info, if (((base_vma + i) & ~0xfff) == (target & ~0xfff)) { - char *stub_name; + char *stub_name = NULL; if (num_a8_fixes == a8_fix_table_size) { a8_fix_table_size *= 2; - a8_fixes = bfd_realloc (a8_fixes, - sizeof (struct a8_erratum_fix) - * a8_fix_table_size); + a8_fixes = (struct a8_erratum_fix *) + bfd_realloc (a8_fixes, + sizeof (struct a8_erratum_fix) + * a8_fix_table_size); } - stub_name = bfd_malloc (8 + 1 + 8 + 1); - if (stub_name != NULL) - sprintf (stub_name, "%x:%x", section->id, i); + if (num_a8_fixes < prev_num_a8_fixes) + { + /* If we're doing a subsequent scan, + check if we've found the same fix as + before, and try and reuse the stub + name. */ + stub_name = a8_fixes[num_a8_fixes].stub_name; + if ((a8_fixes[num_a8_fixes].section != section) + || (a8_fixes[num_a8_fixes].offset != i)) + { + free (stub_name); + stub_name = NULL; + *stub_changed_p = TRUE; + } + } + + if (!stub_name) + { + stub_name = (char *) bfd_malloc (8 + 1 + 8 + 1); + if (stub_name != NULL) + sprintf (stub_name, "%x:%x", section->id, i); + } a8_fixes[num_a8_fixes].input_bfd = input_bfd; a8_fixes[num_a8_fixes].section = section; @@ -4143,7 +4204,7 @@ cortex_a8_erratum_scan (bfd *input_bfd, struct bfd_link_info *info, *num_a8_fixes_p = num_a8_fixes; *a8_fix_table_size_p = a8_fix_table_size; - return 0; + return FALSE; } /* Determine and set the size of the stub section for a final link. @@ -4162,19 +4223,18 @@ elf32_arm_size_stubs (bfd *output_bfd, { bfd_size_type stub_group_size; bfd_boolean stubs_always_after_branch; - bfd_boolean stub_changed = 0; struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info); struct a8_erratum_fix *a8_fixes = NULL; - unsigned int num_a8_fixes = 0, prev_num_a8_fixes = 0, a8_fix_table_size = 10; + unsigned int num_a8_fixes = 0, a8_fix_table_size = 10; struct a8_erratum_reloc *a8_relocs = NULL; unsigned int num_a8_relocs = 0, a8_reloc_table_size = 10, i; if (htab->fix_cortex_a8) { - a8_fixes = bfd_zmalloc (sizeof (struct a8_erratum_fix) - * a8_fix_table_size); - a8_relocs = bfd_zmalloc (sizeof (struct a8_erratum_reloc) - * a8_reloc_table_size); + a8_fixes = (struct a8_erratum_fix *) + bfd_zmalloc (sizeof (struct a8_erratum_fix) * a8_fix_table_size); + a8_relocs = (struct a8_erratum_reloc *) + bfd_zmalloc (sizeof (struct a8_erratum_reloc) * a8_reloc_table_size); } /* Propagate mach to stub bfd, because it may not have been @@ -4215,14 +4275,25 @@ elf32_arm_size_stubs (bfd *output_bfd, group_sections (htab, stub_group_size, stubs_always_after_branch); + /* If we're applying the cortex A8 fix, we need to determine the + program header size now, because we cannot change it later -- + that could alter section placements. Notice the A8 erratum fix + ends up requiring the section addresses to remain unchanged + modulo the page size. That's something we cannot represent + inside BFD, and we don't want to force the section alignment to + be the page size. */ + if (htab->fix_cortex_a8) + (*htab->layout_sections_again) (); + while (1) { bfd *input_bfd; unsigned int bfd_indx; asection *stub_sec; + bfd_boolean stub_changed = FALSE; + unsigned prev_num_a8_fixes = num_a8_fixes; num_a8_fixes = 0; - for (input_bfd = info->input_bfds, bfd_indx = 0; input_bfd != NULL; input_bfd = input_bfd->link_next, bfd_indx++) @@ -4334,6 +4405,11 @@ elf32_arm_size_stubs (bfd *output_bfd, sym = local_syms + r_indx; hdr = elf_elfsections (input_bfd)[sym->st_shndx]; sym_sec = hdr->bfd_section; + if (!sym_sec) + /* 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 @@ -4364,7 +4440,25 @@ elf32_arm_size_stubs (bfd *output_bfd, { sym_sec = hash->root.root.u.def.section; sym_value = hash->root.root.u.def.value; - if (sym_sec->output_section != NULL) + + struct elf32_arm_link_hash_table *globals = + elf32_arm_hash_table (info); + + /* For a destination in a shared library, + use the PLT stub as target address to + decide whether a branch stub is + needed. */ + if (globals->splt != NULL && hash != NULL + && hash->root.plt.offset != (bfd_vma) -1) + { + sym_sec = globals->splt; + sym_value = hash->root.plt.offset; + if (sym_sec->output_section != NULL) + destination = (sym_value + + sym_sec->output_offset + + sym_sec->output_section->vma); + } + else if (sym_sec->output_section != NULL) destination = (sym_value + irela->r_addend + sym_sec->output_offset + sym_sec->output_section->vma); @@ -4431,6 +4525,7 @@ elf32_arm_size_stubs (bfd *output_bfd, { /* The proper stub has already been created. */ free (stub_name); + stub_entry->target_value = sym_value; break; } @@ -4450,8 +4545,8 @@ elf32_arm_size_stubs (bfd *output_bfd, if (sym_name == NULL) sym_name = "unnamed"; - stub_entry->output_name - = bfd_alloc (htab->stub_bfd, + stub_entry->output_name = (char *) + bfd_alloc (htab->stub_bfd, sizeof (THUMB2ARM_GLUE_ENTRY_NAME) + strlen (sym_name)); if (stub_entry->output_name == NULL) @@ -4502,9 +4597,10 @@ elf32_arm_size_stubs (bfd *output_bfd, if (num_a8_relocs == a8_reloc_table_size) { a8_reloc_table_size *= 2; - a8_relocs = bfd_realloc (a8_relocs, - sizeof (struct a8_erratum_reloc) - * a8_reloc_table_size); + a8_relocs = (struct a8_erratum_reloc *) + bfd_realloc (a8_relocs, + sizeof (struct a8_erratum_reloc) + * a8_reloc_table_size); } a8_relocs[num_a8_relocs].from = from; @@ -4527,18 +4623,21 @@ elf32_arm_size_stubs (bfd *output_bfd, if (htab->fix_cortex_a8) { /* Sort relocs which might apply to Cortex-A8 erratum. */ - qsort (a8_relocs, num_a8_relocs, sizeof (struct a8_erratum_reloc), + qsort (a8_relocs, num_a8_relocs, + sizeof (struct a8_erratum_reloc), &a8_reloc_compare); /* Scan for branches which might trigger Cortex-A8 erratum. */ if (cortex_a8_erratum_scan (input_bfd, info, &a8_fixes, &num_a8_fixes, &a8_fix_table_size, - a8_relocs, num_a8_relocs) != 0) + a8_relocs, num_a8_relocs, + prev_num_a8_fixes, &stub_changed) + != 0) goto error_ret_free_local; } } - if (htab->fix_cortex_a8 && num_a8_fixes != prev_num_a8_fixes) + if (prev_num_a8_fixes != num_a8_fixes) stub_changed = TRUE; if (!stub_changed) @@ -4577,8 +4676,6 @@ elf32_arm_size_stubs (bfd *output_bfd, /* Ask the linker to do its stuff. */ (*htab->layout_sections_again) (); - stub_changed = FALSE; - prev_num_a8_fixes = num_a8_fixes; } /* Add stubs for Cortex-A8 erratum fixes now. */ @@ -4592,7 +4689,7 @@ elf32_arm_size_stubs (bfd *output_bfd, unsigned int section_id = a8_fixes[i].section->id; asection *link_sec = htab->stub_group[section_id].link_sec; asection *stub_sec = htab->stub_group[section_id].stub_sec; - const insn_sequence *template; + const insn_sequence *template_sequence; int template_size, size = 0; stub_entry = arm_stub_hash_lookup (&htab->stub_hash_table, stub_name, @@ -4615,11 +4712,12 @@ elf32_arm_size_stubs (bfd *output_bfd, stub_entry->orig_insn = a8_fixes[i].orig_insn; stub_entry->st_type = STT_ARM_TFUNC; - size = find_stub_size_and_template (a8_fixes[i].stub_type, &template, + size = find_stub_size_and_template (a8_fixes[i].stub_type, + &template_sequence, &template_size); stub_entry->stub_size = size; - stub_entry->stub_template = template; + stub_entry->stub_template = template_sequence; stub_entry->stub_template_size = template_size; } @@ -4666,7 +4764,7 @@ elf32_arm_build_stubs (struct bfd_link_info *info) /* Allocate memory to hold the linker stubs. */ size = stub_sec->size; - stub_sec->contents = bfd_zalloc (htab->stub_bfd, size); + stub_sec->contents = (unsigned char *) bfd_zalloc (htab->stub_bfd, size); if (stub_sec->contents == NULL && size != 0) return FALSE; stub_sec->size = 0; @@ -4675,6 +4773,12 @@ elf32_arm_build_stubs (struct bfd_link_info *info) /* Build the stubs as directed by the stub hash table. */ table = &htab->stub_hash_table; bfd_hash_traverse (table, arm_build_one_stub, info); + if (htab->fix_cortex_a8) + { + /* Place the cortex a8 stubs last. */ + htab->fix_cortex_a8 = -1; + bfd_hash_traverse (table, arm_build_one_stub, info); + } return TRUE; } @@ -4693,8 +4797,8 @@ find_thumb_glue (struct bfd_link_info *link_info, /* We need a pointer to the armelf specific hash table. */ hash_table = elf32_arm_hash_table (link_info); - tmp_name = bfd_malloc ((bfd_size_type) strlen (name) - + strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1); + tmp_name = (char *) bfd_malloc ((bfd_size_type) strlen (name) + + strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1); BFD_ASSERT (tmp_name); @@ -4727,8 +4831,8 @@ find_arm_glue (struct bfd_link_info *link_info, /* We need a pointer to the elfarm specific hash table. */ hash_table = elf32_arm_hash_table (link_info); - tmp_name = bfd_malloc ((bfd_size_type) strlen (name) - + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1); + tmp_name = (char *) bfd_malloc ((bfd_size_type) strlen (name) + + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1); BFD_ASSERT (tmp_name); @@ -4838,7 +4942,7 @@ arm_allocate_glue_section_space (bfd * abfd, bfd_size_type size, const char * na s = bfd_get_section_by_name (abfd, name); BFD_ASSERT (s != NULL); - contents = bfd_alloc (abfd, size); + contents = (bfd_byte *) bfd_alloc (abfd, size); BFD_ASSERT (s->size == size); s->contents = contents; @@ -4897,7 +5001,8 @@ record_arm_to_thumb_glue (struct bfd_link_info * link_info, BFD_ASSERT (s != NULL); - tmp_name = bfd_malloc ((bfd_size_type) strlen (name) + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1); + tmp_name = (char *) bfd_malloc ((bfd_size_type) strlen (name) + + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1); BFD_ASSERT (tmp_name); @@ -4974,7 +5079,8 @@ record_arm_bx_glue (struct bfd_link_info * link_info, int reg) BFD_ASSERT (s != NULL); /* Add symbol for veneer. */ - tmp_name = bfd_malloc ((bfd_size_type) strlen (ARM_BX_GLUE_ENTRY_NAME) + 1); + tmp_name = (char *) + bfd_malloc ((bfd_size_type) strlen (ARM_BX_GLUE_ENTRY_NAME) + 1); BFD_ASSERT (tmp_name); @@ -5011,7 +5117,8 @@ elf32_arm_section_map_add (asection *sec, char type, bfd_vma vma) if (sec_data->map == NULL) { - sec_data->map = bfd_malloc (sizeof (elf32_arm_section_map)); + sec_data->map = (elf32_arm_section_map *) + bfd_malloc (sizeof (elf32_arm_section_map)); sec_data->mapcount = 0; sec_data->mapsize = 1; } @@ -5021,8 +5128,9 @@ elf32_arm_section_map_add (asection *sec, char type, bfd_vma vma) if (sec_data->mapcount > sec_data->mapsize) { sec_data->mapsize *= 2; - sec_data->map = bfd_realloc_or_free (sec_data->map, sec_data->mapsize - * sizeof (elf32_arm_section_map)); + sec_data->map = (elf32_arm_section_map *) + bfd_realloc_or_free (sec_data->map, sec_data->mapsize + * sizeof (elf32_arm_section_map)); } if (sec_data->map) @@ -5065,8 +5173,8 @@ record_vfp11_erratum_veneer (struct bfd_link_info *link_info, BFD_ASSERT (s != NULL); - tmp_name = bfd_malloc ((bfd_size_type) strlen - (VFP11_ERRATUM_VENEER_ENTRY_NAME) + 10); + tmp_name = (char *) bfd_malloc ((bfd_size_type) strlen + (VFP11_ERRATUM_VENEER_ENTRY_NAME) + 10); BFD_ASSERT (tmp_name); @@ -5090,7 +5198,8 @@ record_vfp11_erratum_veneer (struct bfd_link_info *link_info, /* Link veneer back to calling location. */ errcount = ++(sec_data->erratumcount); - newerr = bfd_zmalloc (sizeof (elf32_vfp11_erratum_list)); + newerr = (elf32_vfp11_erratum_list *) + bfd_zmalloc (sizeof (elf32_vfp11_erratum_list)); newerr->type = VFP11_ERRATUM_ARM_VENEER; newerr->vma = -1; @@ -5936,8 +6045,8 @@ bfd_elf32_arm_vfp11_erratum_scan (bfd *abfd, struct bfd_link_info *link_info) if (state == 3) { - elf32_vfp11_erratum_list *newerr - = bfd_zmalloc (sizeof (elf32_vfp11_erratum_list)); + 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); @@ -6005,8 +6114,8 @@ bfd_elf32_arm_vfp11_fix_veneer_locations (bfd *abfd, globals = elf32_arm_hash_table (link_info); - tmp_name = bfd_malloc ((bfd_size_type) strlen - (VFP11_ERRATUM_VENEER_ENTRY_NAME) + 10); + tmp_name = (char *) bfd_malloc ((bfd_size_type) strlen + (VFP11_ERRATUM_VENEER_ENTRY_NAME) + 10); for (sec = abfd->sections; sec != NULL; sec = sec->next) { @@ -6893,7 +7002,6 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, case R_ARM_PC24: /* Arm B/BL instruction. */ case R_ARM_PLT32: { - bfd_vma from; bfd_signed_vma branch_offset; struct elf32_arm_stub_hash_entry *stub_entry = NULL; @@ -6930,6 +7038,8 @@ 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) @@ -6938,6 +7048,9 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, + 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; } from = (input_section->output_section->vma @@ -6998,12 +7111,20 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, signed_addend >>= howto->rightshift; /* A branch to an undefined weak symbol is turned into a jump to - the next instruction unless a PLT entry will be created. */ - if (h && h->root.type == bfd_link_hash_undefweak - && !(splt != NULL && h->plt.offset != (bfd_vma) -1)) + the next instruction unless a PLT entry will be created. + Do the same for local undefined symbols. + The jump to the next instruction is optimized as a NOP depending + on the architecture. */ + if (h ? (h->root.type == bfd_link_hash_undefweak + && !(splt != NULL && h->plt.offset != (bfd_vma) -1)) + : bfd_is_und_section (sym_sec)) { - value = (bfd_get_32 (input_bfd, hit_data) & 0xf0000000) - | 0x0affffff; + value = (bfd_get_32 (input_bfd, hit_data) & 0xf0000000); + + if (arch_has_arm_nop (globals)) + value |= 0x0320f000; + else + value |= 0x01a00000; /* Using pre-UAL nop: mov r0, r0. */ } else { @@ -7163,6 +7284,40 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, return bfd_reloc_ok; } + case R_ARM_THM_PC8: + /* PR 10073: This reloc is not generated by the GNU toolchain, + but it is supported for compatibility with third party libraries + generated by other compilers, specifically the ARM/IAR. */ + { + bfd_vma insn; + bfd_signed_vma relocation; + + insn = bfd_get_16 (input_bfd, hit_data); + + if (globals->use_rel) + addend = (insn & 0x00ff) << 2; + + relocation = value + addend; + relocation -= (input_section->output_section->vma + + input_section->output_offset + + rel->r_offset); + + value = abs (relocation); + + /* We do not check for overflow of this reloc. Although strictly + speaking this is incorrect, it appears to be necessary in order + to work with IAR generated relocs. Since GCC and GAS do not + generate R_ARM_THM_PC8 relocs, the lack of a check should not be + a problem for them. */ + value &= 0x3fc; + + insn = (insn & 0xff00) | (value >> 2); + + bfd_put_16 (input_bfd, insn, hit_data); + + return bfd_reloc_ok; + } + case R_ARM_THM_PC12: /* Corresponds to: ldr.w reg, [pc, #offset]. */ { @@ -7214,15 +7369,25 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, bfd_vma check; bfd_signed_vma signed_check; int bitsize; - int thumb2 = using_thumb2 (globals); + const int thumb2 = using_thumb2 (globals); /* A branch to an undefined weak symbol is turned into a jump to - the next instruction unless a PLT entry will be created. */ + the next instruction unless a PLT entry will be created. + The jump to the next instruction is optimized as a NOP.W for + Thumb-2 enabled architectures. */ if (h && h->root.type == bfd_link_hash_undefweak && !(splt != NULL && h->plt.offset != (bfd_vma) -1)) { - bfd_put_16 (input_bfd, 0xe000, hit_data); - bfd_put_16 (input_bfd, 0xbf00, hit_data + 2); + if (arch_has_thumb2_nop (globals)) + { + bfd_put_16 (input_bfd, 0xf3af, hit_data); + bfd_put_16 (input_bfd, 0x8000, hit_data + 2); + } + else + { + bfd_put_16 (input_bfd, 0xe000, hit_data); + bfd_put_16 (input_bfd, 0xbf00, hit_data + 2); + } return bfd_reloc_ok; } @@ -7302,10 +7467,14 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, /* 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; + { + /* Target the Thumb stub before the ARM PLT entry. */ + value -= PLT_THUMB_STUB_SIZE; + sym_flags = STT_ARM_TFUNC; + } *unresolved_reloc_p = FALSE; } @@ -7935,7 +8104,7 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, (_("%B(%A+0x%lx): R_ARM_TLS_LE32 relocation not permitted in shared object"), input_bfd, input_section, (long) rel->r_offset, howto->name); - return FALSE; + return (bfd_reloc_status_type) FALSE; } else value = tpoff (info, value); @@ -8612,6 +8781,25 @@ elf32_arm_relocate_section (bfd * output_bfd, sym = local_syms + r_symndx; sym_type = ELF32_ST_TYPE (sym->st_info); sec = local_sections[r_symndx]; + + /* An object file might have a reference to a local + undefined symbol. This is a daft object file, but we + should at least do something about it. V4BX & NONE + relocations do not use the symbol and are explicitly + allowed to use the undefined symbol, so allow those. */ + if (r_type != R_ARM_V4BX + && r_type != R_ARM_NONE + && bfd_is_und_section (sec) + && ELF_ST_BIND (sym->st_info) != STB_WEAK) + { + if (!info->callbacks->undefined_symbol + (info, bfd_elf_string_from_elf_section + (input_bfd, symtab_hdr->sh_link, sym->st_name), + input_bfd, input_section, + rel->r_offset, TRUE)) + return FALSE; + } + if (globals->use_rel) { relocation = (sec->output_section->vma @@ -8866,7 +9054,8 @@ add_unwind_table_edit (arm_unwind_table_edit **head, asection *linked_section, unsigned int index) { - arm_unwind_table_edit *new_edit = xmalloc (sizeof (arm_unwind_table_edit)); + arm_unwind_table_edit *new_edit = (arm_unwind_table_edit *) + xmalloc (sizeof (arm_unwind_table_edit)); new_edit->type = type; new_edit->linked_section = linked_section; @@ -8960,7 +9149,7 @@ elf32_arm_fix_exidx_coverage (asection **text_section_order, struct bfd_elf_section_data *elf_sec = elf_section_data (sec); Elf_Internal_Shdr *hdr = &elf_sec->this_hdr; - if (hdr->sh_type != SHT_ARM_EXIDX) + if (!hdr || hdr->sh_type != SHT_ARM_EXIDX) continue; if (elf_sec->linked_to) @@ -9363,7 +9552,7 @@ set_secondary_compatible_arch (bfd *abfd, int arch) /* Note: the tag and its argument below are uleb128 values, though currently-defined values fit in one byte for each. */ if (!attr->s) - attr->s = bfd_alloc (abfd, 3); + attr->s = (char *) bfd_alloc (abfd, 3); attr->s[0] = Tag_CPU_arch; attr->s[1] = arch; attr->s[2] = '\0'; @@ -10019,301 +10208,83 @@ elf32_arm_versions_compatible (unsigned iver, unsigned over) object file when linking. */ static bfd_boolean -elf32_arm_merge_private_bfd_data (bfd * ibfd, bfd * obfd) -{ - flagword out_flags; - flagword in_flags; - bfd_boolean flags_compatible = TRUE; - asection *sec; +elf32_arm_merge_private_bfd_data (bfd * ibfd, bfd * obfd); - /* Check if we have the same endianess. */ - if (! _bfd_generic_verify_endian_match (ibfd, obfd)) - return FALSE; +/* Display the flags field. */ - if (! is_arm_elf (ibfd) || ! is_arm_elf (obfd)) - return TRUE; +static bfd_boolean +elf32_arm_print_private_bfd_data (bfd *abfd, void * ptr) +{ + FILE * file = (FILE *) ptr; + unsigned long flags; - if (!elf32_arm_merge_eabi_attributes (ibfd, obfd)) - return FALSE; + BFD_ASSERT (abfd != NULL && ptr != NULL); - /* The input BFD must have had its flags initialised. */ - /* The following seems bogus to me -- The flags are initialized in - the assembler but I don't think an elf_flags_init field is - written into the object. */ - /* BFD_ASSERT (elf_flags_init (ibfd)); */ + /* Print normal ELF private data. */ + _bfd_elf_print_private_bfd_data (abfd, ptr); - in_flags = elf_elfheader (ibfd)->e_flags; - out_flags = elf_elfheader (obfd)->e_flags; + flags = elf_elfheader (abfd)->e_flags; + /* Ignore init flag - it may not be set, despite the flags field + containing valid data. */ - /* In theory there is no reason why we couldn't handle this. However - in practice it isn't even close to working and there is no real - reason to want it. */ - if (EF_ARM_EABI_VERSION (in_flags) >= EF_ARM_EABI_VER4 - && !(ibfd->flags & DYNAMIC) - && (in_flags & EF_ARM_BE8)) - { - _bfd_error_handler (_("error: %B is already in final BE8 format"), - ibfd); - return FALSE; - } + /* xgettext:c-format */ + fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags); - if (!elf_flags_init (obfd)) + switch (EF_ARM_EABI_VERSION (flags)) { - /* If the input is the default architecture and had the default - flags then do not bother setting the flags for the output - architecture, instead allow future merges to do this. If no - future merges ever set these flags then they will retain their - uninitialised values, which surprise surprise, correspond - to the default values. */ - if (bfd_get_arch_info (ibfd)->the_default - && elf_elfheader (ibfd)->e_flags == 0) - return TRUE; + case EF_ARM_EABI_UNKNOWN: + /* The following flag bits are GNU extensions and not part of the + official ARM ELF extended ABI. Hence they are only decoded if + the EABI version is not set. */ + if (flags & EF_ARM_INTERWORK) + fprintf (file, _(" [interworking enabled]")); - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = in_flags; + if (flags & EF_ARM_APCS_26) + fprintf (file, " [APCS-26]"); + else + fprintf (file, " [APCS-32]"); - if (bfd_get_arch (obfd) == bfd_get_arch (ibfd) - && bfd_get_arch_info (obfd)->the_default) - return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd)); + if (flags & EF_ARM_VFP_FLOAT) + fprintf (file, _(" [VFP float format]")); + else if (flags & EF_ARM_MAVERICK_FLOAT) + fprintf (file, _(" [Maverick float format]")); + else + fprintf (file, _(" [FPA float format]")); - return TRUE; - } + if (flags & EF_ARM_APCS_FLOAT) + fprintf (file, _(" [floats passed in float registers]")); - /* Determine what should happen if the input ARM architecture - does not match the output ARM architecture. */ - if (! bfd_arm_merge_machines (ibfd, obfd)) - return FALSE; + if (flags & EF_ARM_PIC) + fprintf (file, _(" [position independent]")); - /* Identical flags must be compatible. */ - if (in_flags == out_flags) - return TRUE; + if (flags & EF_ARM_NEW_ABI) + fprintf (file, _(" [new ABI]")); - /* Check to see if the input BFD actually contains any sections. If - not, its flags may not have been initialised either, but it - cannot actually cause any incompatiblity. Do not short-circuit - dynamic objects; their section list may be emptied by - elf_link_add_object_symbols. + if (flags & EF_ARM_OLD_ABI) + fprintf (file, _(" [old ABI]")); - Also check to see if there are no code sections in the input. - In this case there is no need to check for code specific flags. - XXX - do we need to worry about floating-point format compatability - in data sections ? */ - if (!(ibfd->flags & DYNAMIC)) - { - bfd_boolean null_input_bfd = TRUE; - bfd_boolean only_data_sections = TRUE; + if (flags & EF_ARM_SOFT_FLOAT) + fprintf (file, _(" [software FP]")); - for (sec = ibfd->sections; sec != NULL; sec = sec->next) - { - /* Ignore synthetic glue sections. */ - if (strcmp (sec->name, ".glue_7") - && strcmp (sec->name, ".glue_7t")) - { - if ((bfd_get_section_flags (ibfd, sec) - & (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS)) - == (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS)) - only_data_sections = FALSE; + flags &= ~(EF_ARM_INTERWORK | EF_ARM_APCS_26 | EF_ARM_APCS_FLOAT + | EF_ARM_PIC | EF_ARM_NEW_ABI | EF_ARM_OLD_ABI + | EF_ARM_SOFT_FLOAT | EF_ARM_VFP_FLOAT + | EF_ARM_MAVERICK_FLOAT); + break; - null_input_bfd = FALSE; - break; - } - } + case EF_ARM_EABI_VER1: + fprintf (file, _(" [Version1 EABI]")); - if (null_input_bfd || only_data_sections) - return TRUE; - } + if (flags & EF_ARM_SYMSARESORTED) + fprintf (file, _(" [sorted symbol table]")); + else + fprintf (file, _(" [unsorted symbol table]")); - /* Complain about various flag mismatches. */ - if (!elf32_arm_versions_compatible (EF_ARM_EABI_VERSION (in_flags), - EF_ARM_EABI_VERSION (out_flags))) - { - _bfd_error_handler - (_("error: Source object %B has EABI version %d, but target %B has EABI version %d"), - ibfd, obfd, - (in_flags & EF_ARM_EABIMASK) >> 24, - (out_flags & EF_ARM_EABIMASK) >> 24); - return FALSE; - } + flags &= ~ EF_ARM_SYMSARESORTED; + break; - /* Not sure what needs to be checked for EABI versions >= 1. */ - /* VxWorks libraries do not use these flags. */ - if (get_elf_backend_data (obfd) != &elf32_arm_vxworks_bed - && get_elf_backend_data (ibfd) != &elf32_arm_vxworks_bed - && EF_ARM_EABI_VERSION (in_flags) == EF_ARM_EABI_UNKNOWN) - { - if ((in_flags & EF_ARM_APCS_26) != (out_flags & EF_ARM_APCS_26)) - { - _bfd_error_handler - (_("error: %B is compiled for APCS-%d, whereas target %B uses APCS-%d"), - ibfd, obfd, - in_flags & EF_ARM_APCS_26 ? 26 : 32, - out_flags & EF_ARM_APCS_26 ? 26 : 32); - flags_compatible = FALSE; - } - - if ((in_flags & EF_ARM_APCS_FLOAT) != (out_flags & EF_ARM_APCS_FLOAT)) - { - if (in_flags & EF_ARM_APCS_FLOAT) - _bfd_error_handler - (_("error: %B passes floats in float registers, whereas %B passes them in integer registers"), - ibfd, obfd); - else - _bfd_error_handler - (_("error: %B passes floats in integer registers, whereas %B passes them in float registers"), - ibfd, obfd); - - flags_compatible = FALSE; - } - - if ((in_flags & EF_ARM_VFP_FLOAT) != (out_flags & EF_ARM_VFP_FLOAT)) - { - if (in_flags & EF_ARM_VFP_FLOAT) - _bfd_error_handler - (_("error: %B uses VFP instructions, whereas %B does not"), - ibfd, obfd); - else - _bfd_error_handler - (_("error: %B uses FPA instructions, whereas %B does not"), - ibfd, obfd); - - flags_compatible = FALSE; - } - - if ((in_flags & EF_ARM_MAVERICK_FLOAT) != (out_flags & EF_ARM_MAVERICK_FLOAT)) - { - if (in_flags & EF_ARM_MAVERICK_FLOAT) - _bfd_error_handler - (_("error: %B uses Maverick instructions, whereas %B does not"), - ibfd, obfd); - else - _bfd_error_handler - (_("error: %B does not use Maverick instructions, whereas %B does"), - ibfd, obfd); - - flags_compatible = FALSE; - } - -#ifdef EF_ARM_SOFT_FLOAT - if ((in_flags & EF_ARM_SOFT_FLOAT) != (out_flags & EF_ARM_SOFT_FLOAT)) - { - /* We can allow interworking between code that is VFP format - layout, and uses either soft float or integer regs for - passing floating point arguments and results. We already - know that the APCS_FLOAT flags match; similarly for VFP - flags. */ - if ((in_flags & EF_ARM_APCS_FLOAT) != 0 - || (in_flags & EF_ARM_VFP_FLOAT) == 0) - { - if (in_flags & EF_ARM_SOFT_FLOAT) - _bfd_error_handler - (_("error: %B uses software FP, whereas %B uses hardware FP"), - ibfd, obfd); - else - _bfd_error_handler - (_("error: %B uses hardware FP, whereas %B uses software FP"), - ibfd, obfd); - - flags_compatible = FALSE; - } - } -#endif - - /* Interworking mismatch is only a warning. */ - if ((in_flags & EF_ARM_INTERWORK) != (out_flags & EF_ARM_INTERWORK)) - { - if (in_flags & EF_ARM_INTERWORK) - { - _bfd_error_handler - (_("Warning: %B supports interworking, whereas %B does not"), - ibfd, obfd); - } - else - { - _bfd_error_handler - (_("Warning: %B does not support interworking, whereas %B does"), - ibfd, obfd); - } - } - } - - return flags_compatible; -} - -/* Display the flags field. */ - -static bfd_boolean -elf32_arm_print_private_bfd_data (bfd *abfd, void * ptr) -{ - FILE * file = (FILE *) ptr; - unsigned long flags; - - BFD_ASSERT (abfd != NULL && ptr != NULL); - - /* Print normal ELF private data. */ - _bfd_elf_print_private_bfd_data (abfd, ptr); - - flags = elf_elfheader (abfd)->e_flags; - /* Ignore init flag - it may not be set, despite the flags field - containing valid data. */ - - /* xgettext:c-format */ - fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags); - - switch (EF_ARM_EABI_VERSION (flags)) - { - case EF_ARM_EABI_UNKNOWN: - /* The following flag bits are GNU extensions and not part of the - official ARM ELF extended ABI. Hence they are only decoded if - the EABI version is not set. */ - if (flags & EF_ARM_INTERWORK) - fprintf (file, _(" [interworking enabled]")); - - if (flags & EF_ARM_APCS_26) - fprintf (file, " [APCS-26]"); - else - fprintf (file, " [APCS-32]"); - - if (flags & EF_ARM_VFP_FLOAT) - fprintf (file, _(" [VFP float format]")); - else if (flags & EF_ARM_MAVERICK_FLOAT) - fprintf (file, _(" [Maverick float format]")); - else - fprintf (file, _(" [FPA float format]")); - - if (flags & EF_ARM_APCS_FLOAT) - fprintf (file, _(" [floats passed in float registers]")); - - if (flags & EF_ARM_PIC) - fprintf (file, _(" [position independent]")); - - if (flags & EF_ARM_NEW_ABI) - fprintf (file, _(" [new ABI]")); - - if (flags & EF_ARM_OLD_ABI) - fprintf (file, _(" [old ABI]")); - - if (flags & EF_ARM_SOFT_FLOAT) - fprintf (file, _(" [software FP]")); - - flags &= ~(EF_ARM_INTERWORK | EF_ARM_APCS_26 | EF_ARM_APCS_FLOAT - | EF_ARM_PIC | EF_ARM_NEW_ABI | EF_ARM_OLD_ABI - | EF_ARM_SOFT_FLOAT | EF_ARM_VFP_FLOAT - | EF_ARM_MAVERICK_FLOAT); - break; - - case EF_ARM_EABI_VER1: - fprintf (file, _(" [Version1 EABI]")); - - if (flags & EF_ARM_SYMSARESORTED) - fprintf (file, _(" [sorted symbol table]")); - else - fprintf (file, _(" [unsorted symbol table]")); - - flags &= ~ EF_ARM_SYMSARESORTED; - break; - - case EF_ARM_EABI_VER2: - fprintf (file, _(" [Version2 EABI]")); + case EF_ARM_EABI_VER2: + fprintf (file, _(" [Version2 EABI]")); if (flags & EF_ARM_SYMSARESORTED) fprintf (file, _(" [sorted symbol table]")); @@ -10662,7 +10633,8 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, size = symtab_hdr->sh_info; size *= (sizeof (bfd_signed_vma) + sizeof (char)); - local_got_refcounts = bfd_zalloc (abfd, size); + local_got_refcounts = (bfd_signed_vma *) + bfd_zalloc (abfd, size); if (local_got_refcounts == NULL) return FALSE; elf_local_got_refcounts (abfd) = local_got_refcounts; @@ -10839,15 +10811,19 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, /* Track dynamic relocs needed for local syms too. We really need local syms available to do this easily. Oh well. */ - asection *s; void *vpp; + Elf_Internal_Sym *isym; - s = bfd_section_from_r_symndx (abfd, &htab->sym_sec, - sec, r_symndx); - if (s == NULL) + isym = bfd_sym_from_r_symndx (&htab->sym_cache, + abfd, r_symndx); + if (isym == NULL) return FALSE; + s = bfd_section_from_elf_index (abfd, isym->st_shndx); + if (s == NULL) + s = sec; + vpp = &elf_section_data (s)->local_dynrel; head = (struct elf32_arm_relocs_copied **) vpp; } @@ -10857,7 +10833,8 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, { bfd_size_type amt = sizeof *p; - p = bfd_alloc (htab->root.dynobj, amt); + p = (struct elf32_arm_relocs_copied *) + bfd_alloc (htab->root.dynobj, amt); if (p == NULL) return FALSE; p->next = *head; @@ -11631,7 +11608,8 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED, { struct elf32_arm_relocs_copied *p; - for (p = elf_section_data (s)->local_dynrel; p != NULL; p = p->next) + for (p = (struct elf32_arm_relocs_copied *) + elf_section_data (s)->local_dynrel; p != NULL; p = p->next) { if (!bfd_is_abs_section (p->section) && bfd_is_abs_section (p->section->output_section)) @@ -11785,7 +11763,7 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED, continue; /* Allocate memory for the section contents. */ - s->contents = bfd_zalloc (dynobj, s->size); + s->contents = (unsigned char *) bfd_zalloc (dynobj, s->size); if (s->contents == NULL) return FALSE; } @@ -12580,7 +12558,7 @@ record_section_with_arm_elf_section_data (asection * sec) { struct section_list * entry; - entry = bfd_malloc (sizeof (* entry)); + entry = (struct section_list *) bfd_malloc (sizeof (* entry)); if (entry == NULL) return; entry->sec = sec; @@ -12807,7 +12785,7 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry, bfd_vma addr; char *stub_name; output_arch_syminfo *osi; - const insn_sequence *template; + const insn_sequence *template_sequence; enum stub_insn_type prev_type; int size; int i; @@ -12830,8 +12808,8 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry, addr = (bfd_vma) stub_entry->stub_offset; stub_name = stub_entry->output_name; - template = stub_entry->stub_template; - switch (template[0].type) + template_sequence = stub_entry->stub_template; + switch (template_sequence[0].type) { case ARM_TYPE: if (!elf32_arm_output_stub_sym (osi, stub_name, addr, stub_entry->stub_size)) @@ -12852,7 +12830,7 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry, size = 0; for (i = 0; i < stub_entry->stub_template_size; i++) { - switch (template[i].type) + switch (template_sequence[i].type) { case ARM_TYPE: sym_type = ARM_MAP_ARM; @@ -12872,14 +12850,14 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry, return FALSE; } - if (template[i].type != prev_type) + if (template_sequence[i].type != prev_type) { - prev_type = template[i].type; + prev_type = template_sequence[i].type; if (!elf32_arm_output_map_sym (osi, sym_type, addr + size)) return FALSE; } - switch (template[i].type) + switch (template_sequence[i].type) { case ARM_TYPE: case THUMB32_TYPE: @@ -13044,7 +13022,7 @@ elf32_arm_new_section_hook (bfd *abfd, asection *sec) _arm_elf_section_data *sdata; bfd_size_type amt = sizeof (*sdata); - sdata = bfd_zalloc (abfd, amt); + sdata = (_arm_elf_section_data *) bfd_zalloc (abfd, amt); if (sdata == NULL) return FALSE; sec->used_by_bfd = sdata; @@ -13336,7 +13314,7 @@ elf32_arm_write_section (bfd *output_bfd, size (before we merged duplicate entries and inserted EXIDX_CANTUNWIND markers) was sec->rawsize. (This isn't the case if we perform no edits, then rawsize will be zero and we should use size). */ - bfd_byte *edited_contents = bfd_malloc (sec->size); + bfd_byte *edited_contents = (bfd_byte *) bfd_malloc (sec->size); unsigned int input_size = sec->rawsize ? sec->rawsize : sec->size; unsigned int in_index, out_index; bfd_vma add_to_offsets = 0; @@ -13609,7 +13587,8 @@ elf32_arm_modify_segment_map (bfd *abfd, m = m->next; if (!m) { - m = bfd_zalloc (abfd, sizeof (struct elf_segment_map)); + m = (struct elf_segment_map *) + bfd_zalloc (abfd, sizeof (struct elf_segment_map)); if (m == NULL) return FALSE; m->p_type = PT_ARM_EXIDX; @@ -13821,6 +13800,231 @@ elf32_arm_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker) #include "elf32-target.h" +/* Merge backend specific data from an object file to the output + object file when linking. */ + +static bfd_boolean +elf32_arm_merge_private_bfd_data (bfd * ibfd, bfd * obfd) +{ + flagword out_flags; + flagword in_flags; + bfd_boolean flags_compatible = TRUE; + asection *sec; + + /* Check if we have the same endianess. */ + if (! _bfd_generic_verify_endian_match (ibfd, obfd)) + return FALSE; + + if (! is_arm_elf (ibfd) || ! is_arm_elf (obfd)) + return TRUE; + + if (!elf32_arm_merge_eabi_attributes (ibfd, obfd)) + return FALSE; + + /* The input BFD must have had its flags initialised. */ + /* The following seems bogus to me -- The flags are initialized in + the assembler but I don't think an elf_flags_init field is + written into the object. */ + /* BFD_ASSERT (elf_flags_init (ibfd)); */ + + in_flags = elf_elfheader (ibfd)->e_flags; + out_flags = elf_elfheader (obfd)->e_flags; + + /* In theory there is no reason why we couldn't handle this. However + in practice it isn't even close to working and there is no real + reason to want it. */ + if (EF_ARM_EABI_VERSION (in_flags) >= EF_ARM_EABI_VER4 + && !(ibfd->flags & DYNAMIC) + && (in_flags & EF_ARM_BE8)) + { + _bfd_error_handler (_("error: %B is already in final BE8 format"), + ibfd); + return FALSE; + } + + if (!elf_flags_init (obfd)) + { + /* If the input is the default architecture and had the default + flags then do not bother setting the flags for the output + architecture, instead allow future merges to do this. If no + future merges ever set these flags then they will retain their + uninitialised values, which surprise surprise, correspond + to the default values. */ + if (bfd_get_arch_info (ibfd)->the_default + && elf_elfheader (ibfd)->e_flags == 0) + return TRUE; + + elf_flags_init (obfd) = TRUE; + elf_elfheader (obfd)->e_flags = in_flags; + + if (bfd_get_arch (obfd) == bfd_get_arch (ibfd) + && bfd_get_arch_info (obfd)->the_default) + return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd)); + + return TRUE; + } + + /* Determine what should happen if the input ARM architecture + does not match the output ARM architecture. */ + if (! bfd_arm_merge_machines (ibfd, obfd)) + return FALSE; + + /* Identical flags must be compatible. */ + if (in_flags == out_flags) + return TRUE; + + /* Check to see if the input BFD actually contains any sections. If + not, its flags may not have been initialised either, but it + cannot actually cause any incompatiblity. Do not short-circuit + dynamic objects; their section list may be emptied by + elf_link_add_object_symbols. + + Also check to see if there are no code sections in the input. + In this case there is no need to check for code specific flags. + XXX - do we need to worry about floating-point format compatability + in data sections ? */ + if (!(ibfd->flags & DYNAMIC)) + { + bfd_boolean null_input_bfd = TRUE; + bfd_boolean only_data_sections = TRUE; + + for (sec = ibfd->sections; sec != NULL; sec = sec->next) + { + /* Ignore synthetic glue sections. */ + if (strcmp (sec->name, ".glue_7") + && strcmp (sec->name, ".glue_7t")) + { + if ((bfd_get_section_flags (ibfd, sec) + & (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS)) + == (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS)) + only_data_sections = FALSE; + + null_input_bfd = FALSE; + break; + } + } + + if (null_input_bfd || only_data_sections) + return TRUE; + } + + /* Complain about various flag mismatches. */ + if (!elf32_arm_versions_compatible (EF_ARM_EABI_VERSION (in_flags), + EF_ARM_EABI_VERSION (out_flags))) + { + _bfd_error_handler + (_("error: Source object %B has EABI version %d, but target %B has EABI version %d"), + ibfd, obfd, + (in_flags & EF_ARM_EABIMASK) >> 24, + (out_flags & EF_ARM_EABIMASK) >> 24); + return FALSE; + } + + /* Not sure what needs to be checked for EABI versions >= 1. */ + /* VxWorks libraries do not use these flags. */ + if (get_elf_backend_data (obfd) != &elf32_arm_vxworks_bed + && get_elf_backend_data (ibfd) != &elf32_arm_vxworks_bed + && EF_ARM_EABI_VERSION (in_flags) == EF_ARM_EABI_UNKNOWN) + { + if ((in_flags & EF_ARM_APCS_26) != (out_flags & EF_ARM_APCS_26)) + { + _bfd_error_handler + (_("error: %B is compiled for APCS-%d, whereas target %B uses APCS-%d"), + ibfd, obfd, + in_flags & EF_ARM_APCS_26 ? 26 : 32, + out_flags & EF_ARM_APCS_26 ? 26 : 32); + flags_compatible = FALSE; + } + + if ((in_flags & EF_ARM_APCS_FLOAT) != (out_flags & EF_ARM_APCS_FLOAT)) + { + if (in_flags & EF_ARM_APCS_FLOAT) + _bfd_error_handler + (_("error: %B passes floats in float registers, whereas %B passes them in integer registers"), + ibfd, obfd); + else + _bfd_error_handler + (_("error: %B passes floats in integer registers, whereas %B passes them in float registers"), + ibfd, obfd); + + flags_compatible = FALSE; + } + + if ((in_flags & EF_ARM_VFP_FLOAT) != (out_flags & EF_ARM_VFP_FLOAT)) + { + if (in_flags & EF_ARM_VFP_FLOAT) + _bfd_error_handler + (_("error: %B uses VFP instructions, whereas %B does not"), + ibfd, obfd); + else + _bfd_error_handler + (_("error: %B uses FPA instructions, whereas %B does not"), + ibfd, obfd); + + flags_compatible = FALSE; + } + + if ((in_flags & EF_ARM_MAVERICK_FLOAT) != (out_flags & EF_ARM_MAVERICK_FLOAT)) + { + if (in_flags & EF_ARM_MAVERICK_FLOAT) + _bfd_error_handler + (_("error: %B uses Maverick instructions, whereas %B does not"), + ibfd, obfd); + else + _bfd_error_handler + (_("error: %B does not use Maverick instructions, whereas %B does"), + ibfd, obfd); + + flags_compatible = FALSE; + } + +#ifdef EF_ARM_SOFT_FLOAT + if ((in_flags & EF_ARM_SOFT_FLOAT) != (out_flags & EF_ARM_SOFT_FLOAT)) + { + /* We can allow interworking between code that is VFP format + layout, and uses either soft float or integer regs for + passing floating point arguments and results. We already + know that the APCS_FLOAT flags match; similarly for VFP + flags. */ + if ((in_flags & EF_ARM_APCS_FLOAT) != 0 + || (in_flags & EF_ARM_VFP_FLOAT) == 0) + { + if (in_flags & EF_ARM_SOFT_FLOAT) + _bfd_error_handler + (_("error: %B uses software FP, whereas %B uses hardware FP"), + ibfd, obfd); + else + _bfd_error_handler + (_("error: %B uses hardware FP, whereas %B uses software FP"), + ibfd, obfd); + + flags_compatible = FALSE; + } + } +#endif + + /* Interworking mismatch is only a warning. */ + if ((in_flags & EF_ARM_INTERWORK) != (out_flags & EF_ARM_INTERWORK)) + { + if (in_flags & EF_ARM_INTERWORK) + { + _bfd_error_handler + (_("Warning: %B supports interworking, whereas %B does not"), + ibfd, obfd); + } + else + { + _bfd_error_handler + (_("Warning: %B does not support interworking, whereas %B does"), + ibfd, obfd); + } + } + } + + return flags_compatible; +} + + /* Symbian OS Targets. */ #undef TARGET_LITTLE_SYM