/* 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.
#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,
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;
((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
{
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;
/* 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;
/* 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;
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;
}
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;
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;
}
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;
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;
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)
{
/* We have an extra 2-bytes reach because of
the mode change (bit 24 (H) of BLX encoding). */
- if ((branch_offset > (ARM_MAX_FWD_BRANCH_OFFSET + 2)
- || (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET)
- || ((r_type == R_ARM_CALL) && !globals->use_blx)
- || (r_type == R_ARM_JUMP24)
- || (r_type == R_ARM_PLT32))
- && !use_plt)
+ if (branch_offset > (ARM_MAX_FWD_BRANCH_OFFSET + 2)
+ || (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET)
+ || ((r_type == R_ARM_CALL) && !globals->use_blx)
+ || (r_type == R_ARM_JUMP24)
+ || (r_type == R_ARM_PLT32))
{
stub_type = (info->shared | globals->pic_veneer)
/* PIC stubs. */
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,
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,
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;
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};
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;
+ 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)
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;
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;
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;
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[]
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;
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;
}
if (stub_template)
- *stub_template = template;
+ *stub_template = template_sequence;
if (stub_template_size)
*stub_template_size = template_size;
{
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. */
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;
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;
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;
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;
/* 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);
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);
* 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]);
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;
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)
{
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)
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;
}
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;
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;
*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.
{
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
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++)
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
{
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);
{
/* The proper stub has already been created. */
free (stub_name);
+ stub_entry->target_value = sym_value;
break;
}
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)
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;
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)
/* 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. */
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,
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;
}
/* 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;
/* 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;
}
/* 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);
/* 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);
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;
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);
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);
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;
}
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)
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);
/* 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;
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);
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)
{
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;
|| 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)
+ 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
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
{
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]. */
{
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;
}
/* 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;
}
(_("%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);
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
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;
/* 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';
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]"));
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;
/* 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;
}
{
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;
{
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))
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;
}
{
struct section_list * entry;
- entry = bfd_malloc (sizeof (* entry));
+ entry = (struct section_list *) bfd_malloc (sizeof (* entry));
if (entry == NULL)
return;
entry->sec = sec;
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;
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))
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;
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:
_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;
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;
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;
#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