static reloc_howto_type elf32_arm_howto_table_1[] =
{
- /* No relocation */
+ /* No relocation. */
HOWTO (R_ARM_NONE, /* type */
0, /* rightshift */
0, /* size (0 = byte, 1 = short, 2 = long) */
0x040f70ff, /* dst_mask */
FALSE), /* pcrel_offset */
- EMPTY_HOWTO (90), /* unallocated */
+ EMPTY_HOWTO (90), /* Unallocated. */
EMPTY_HOWTO (91),
EMPTY_HOWTO (92),
EMPTY_HOWTO (93),
bfd_reloc_code_real_type code)
{
unsigned int i;
+
for (i = 0; i < ARRAY_SIZE (elf32_arm_reloc_map); i ++)
if (elf32_arm_reloc_map[i].bfd_reloc_val == code)
return elf32_arm_howto_from_type (elf32_arm_reloc_map[i].elf_reloc_val);
default:
return FALSE;
- case 148: /* Linux/ARM 32-bit*/
+ case 148: /* Linux/ARM 32-bit. */
/* pr_cursig */
elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
default:
return FALSE;
- case 124: /* Linux/ARM elf_prpsinfo */
+ case 124: /* Linux/ARM elf_prpsinfo. */
elf_tdata (abfd)->core_program
= _bfd_elfcore_strndup (abfd, note->descdata + 28, 16);
elf_tdata (abfd)->core_command
#define ARM_BX_GLUE_SECTION_NAME ".v4_bx"
#define ARM_BX_GLUE_ENTRY_NAME "__bx_r%d"
+#define STUB_ENTRY_NAME "__%s_veneer"
+
/* The name of the dynamic interpreter. This is put in the .interp
section. */
#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1"
{
0x4e02b540, /* push {r6, lr} */
/* ldr r6, [pc, #8] */
- 0xe7fe46fe, /* mov lr, pc */
- /* b.n r6 */
+ 0x473046fe, /* mov lr, pc */
+ /* bx r6 */
0xbf00bd40, /* pop {r6, pc} */
/* nop */
0x00000000, /* dcd R_ARM_ABS32(X) */
0x00000000, /* dcd R_ARM_ABS32(X) */
};
+static const bfd_vma arm_thumb_arm_v4t_short_branch_stub[] =
+ {
+ 0x46c04778, /* bx pc */
+ /* nop */
+ 0xea000000, /* b (X) */
+ };
+
static const bfd_vma arm_pic_long_branch_stub[] =
{
0xe59fc000, /* ldr r12, [pc] */
0xe08ff00c, /* add pc, pc, ip */
- 0x00000000, /* dcd R_ARM_ABS32(X) */
+ 0x00000000, /* dcd R_ARM_REL32(X) */
};
/* Section name for stubs is the associated section name plus this
arm_thumb_v4t_stub_long_branch,
arm_thumb_thumb_stub_long_branch,
arm_thumb_arm_v4t_stub_long_branch,
+ arm_thumb_arm_v4t_stub_short_branch,
arm_stub_pic_long_branch,
};
/* Where this stub is being called from, or, in the case of combined
stub sections, the first input section in the group. */
asection *id_sec;
+
+ /* The name for the local symbol at the start of this stub. The
+ stub name in the hash table has to be unique; this does not, so
+ it can be friendlier. */
+ char *output_name;
};
/* Used to build a map of a section. This is required for mixed-endian
/* Zero to warn when linking objects with incompatible enum sizes. */
int no_enum_size_warning;
+
+ /* Zero to warn when linking objects with incompatible wchar_t sizes. */
+ int no_wchar_size_warning;
};
#define elf_arm_tdata(bfd) \
symbols with Arm stubs. */
struct elf_link_hash_entry *export_glue;
- /* A pointer to the most recently used stub hash entry against this
- symbol. */
- struct elf32_arm_stub_hash_entry *stub_cache;
+ /* A pointer to the most recently used stub hash entry against this
+ symbol. */
+ struct elf32_arm_stub_hash_entry *stub_cache;
};
/* Traverse an arm ELF linker hash table. */
return entry;
}
-/* Return true if NAME is the name of the relocation section associated
- with S. */
-
-static bfd_boolean
-reloc_section_p (struct elf32_arm_link_hash_table *htab,
- const char *name, asection *s)
-{
- if (htab->use_rel)
- return CONST_STRNEQ (name, ".rel") && strcmp (s->name, name + 4) == 0;
- else
- return CONST_STRNEQ (name, ".rela") && strcmp (s->name, name + 5) == 0;
-}
-
/* Create .got, .gotplt, and .rel(a).got sections in DYNOBJ, and set up
shortcuts to them in our hash table. */
ret->sym_sec.abfd = NULL;
ret->obfd = abfd;
ret->tls_ldm_got.refcount = 0;
+ ret->stub_bfd = NULL;
+ ret->add_stub_section = NULL;
+ ret->layout_sections_again = NULL;
+ ret->stub_group = NULL;
+ ret->bfd_count = 0;
+ ret->top_index = 0;
+ ret->input_list = NULL;
if (!bfd_hash_table_init (&ret->stub_hash_table, stub_hash_newfunc,
sizeof (struct elf32_arm_stub_hash_entry)))
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)
+{
+ switch (stub_type)
+ {
+ case arm_thumb_thumb_stub_long_branch:
+ case arm_thumb_arm_v4t_stub_long_branch:
+ case arm_thumb_arm_v4t_stub_short_branch:
+ return TRUE;
+ case arm_stub_none:
+ BFD_FAIL ();
+ return FALSE;
+ break;
+ default:
+ return FALSE;
+ }
+}
+
/* Determine the type of stub needed, if any, for a call. */
static enum elf32_arm_stub_type
const Elf_Internal_Rela *rel,
unsigned char st_type,
struct elf32_arm_link_hash_entry *hash,
- bfd_vma destination)
+ bfd_vma destination,
+ asection *sym_sec,
+ bfd *input_bfd,
+ const char *name)
{
bfd_vma location;
bfd_signed_vma branch_offset;
int thumb_only;
enum elf32_arm_stub_type stub_type = arm_stub_none;
+ /* We don't know the actual type of destination in case it is of
+ type STT_SECTION: give up. */
+ if (st_type == STT_SECTION)
+ return stub_type;
+
globals = elf32_arm_hash_table (info);
thumb_only = using_thumb_only (globals);
/* If the call will go through a PLT entry then we do not need
glue. */
- if (globals->splt != NULL && hash->root.plt.offset != (bfd_vma) -1)
+ if (globals->splt != NULL && hash != NULL && hash->root.plt.offset != (bfd_vma) -1)
return stub_type;
if (r_type == R_ARM_THM_CALL)
else
{
/* Thumb to arm. */
+ if (sym_sec != NULL
+ && sym_sec->owner != NULL
+ && !INTERWORK_FLAG (sym_sec->owner))
+ {
+ (*_bfd_error_handler)
+ (_("%B(%s): warning: interworking not enabled.\n"
+ " first occurrence: %B: Thumb call to ARM"),
+ sym_sec->owner, input_bfd, name);
+ }
+
stub_type = (info->shared | globals->pic_veneer)
? ((globals->use_blx)
? arm_stub_pic_long_branch
: (globals->use_blx)
? arm_stub_long_branch
: arm_thumb_arm_v4t_stub_long_branch;
+
+ /* Handle v4t short branches. */
+ if ((stub_type == arm_thumb_arm_v4t_stub_long_branch)
+ && (branch_offset <= THM_MAX_FWD_BRANCH_OFFSET)
+ && (branch_offset >= THM_MAX_BWD_BRANCH_OFFSET))
+ stub_type = arm_thumb_arm_v4t_stub_short_branch;
}
}
}
if (st_type == STT_ARM_TFUNC)
{
/* Arm to thumb. */
- /* We have an extra 2-bytes reach because of the mode change
- (bit 24 (H) of BLX encoding). */
+
+ if (sym_sec != NULL
+ && sym_sec->owner != NULL
+ && !INTERWORK_FLAG (sym_sec->owner))
+ {
+ (*_bfd_error_handler)
+ (_("%B(%s): warning: interworking not enabled.\n"
+ " first occurrence: %B: Thumb call to ARM"),
+ sym_sec->owner, input_bfd, name);
+ }
+
+ /* 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)
|| !globals->use_blx)
return stub_entry;
}
-static void elf32_arm_stub_add_mapping_symbol (struct bfd_link_info * link_info,
- asection *stub_sec,
- char* name,
- bfd_vma val)
-{
- struct bfd_link_hash_entry * bh = NULL;
- struct elf_link_hash_entry * myh;
-
- _bfd_generic_link_add_one_symbol (link_info,
- stub_sec->owner, name,
- BSF_LOCAL, stub_sec, stub_sec->size + val,
- NULL, TRUE, FALSE, &bh);
-
- myh = (struct elf_link_hash_entry *) bh;
- myh->type = ELF_ST_INFO (STB_LOCAL, STT_NOTYPE);
- myh->forced_local = 1;
-}
-
/* Add a new stub entry to the stub hash. Not all fields of the new
stub entry are initialised. */
static struct elf32_arm_stub_hash_entry *
elf32_arm_add_stub (const char *stub_name,
asection *section,
- struct elf32_arm_link_hash_table *htab,
- struct bfd_link_info * link_info,
- enum elf32_arm_stub_type stub_type)
+ struct elf32_arm_link_hash_table *htab)
{
asection *link_sec;
asection *stub_sec;
stub_entry->stub_offset = 0;
stub_entry->id_sec = link_sec;
- switch (stub_type)
- {
- case arm_stub_long_branch:
- elf32_arm_stub_add_mapping_symbol (link_info, stub_sec, "$a", 0);
- elf32_arm_stub_add_mapping_symbol (link_info, stub_sec, "$d", 4);
- break;
- case arm_thumb_v4t_stub_long_branch:
- elf32_arm_stub_add_mapping_symbol (link_info, stub_sec, "$a", 0);
- elf32_arm_stub_add_mapping_symbol (link_info, stub_sec, "$d", 8);
- break;
- case arm_thumb_thumb_stub_long_branch:
- elf32_arm_stub_add_mapping_symbol (link_info, stub_sec, "$t", 0);
- elf32_arm_stub_add_mapping_symbol (link_info, stub_sec, "$d", 12);
- break;
- case arm_thumb_arm_v4t_stub_long_branch:
- elf32_arm_stub_add_mapping_symbol (link_info, stub_sec, "$t", 0);
- elf32_arm_stub_add_mapping_symbol (link_info, stub_sec, "$a", 8);
- elf32_arm_stub_add_mapping_symbol (link_info, stub_sec, "$d", 16);
- break;
- case arm_stub_pic_long_branch:
- elf32_arm_stub_add_mapping_symbol (link_info, stub_sec, "$a", 0);
- elf32_arm_stub_add_mapping_symbol (link_info, stub_sec, "$d", 8);
- break;
- default:
- BFD_FAIL ();
- }
-
return stub_entry;
}
elf32_arm_write_section. */
static void
-put_arm_insn (struct elf32_arm_link_hash_table *htab,
- bfd * output_bfd, bfd_vma val, void * ptr)
+put_arm_insn (struct elf32_arm_link_hash_table * htab,
+ bfd * output_bfd, bfd_vma val, void * ptr)
{
if (htab->byteswap_code != bfd_little_endian (output_bfd))
bfd_putl32 (val, ptr);
elf32_arm_write_section. */
static void
-put_thumb_insn (struct elf32_arm_link_hash_table *htab,
- bfd * output_bfd, bfd_vma val, void * ptr)
+put_thumb_insn (struct elf32_arm_link_hash_table * htab,
+ bfd * output_bfd, bfd_vma val, void * ptr)
{
if (htab->byteswap_code != bfd_little_endian (output_bfd))
bfd_putl16 (val, ptr);
template = arm_thumb_arm_v4t_long_branch_stub;
template_size = (sizeof (arm_thumb_arm_v4t_long_branch_stub) / sizeof (bfd_vma)) * 4;
break;
+ case arm_thumb_arm_v4t_stub_short_branch:
+ template = arm_thumb_arm_v4t_short_branch_stub;
+ template_size = (sizeof(arm_thumb_arm_v4t_short_branch_stub) / sizeof (bfd_vma)) * 4;
+ break;
case arm_stub_pic_long_branch:
template = arm_pic_long_branch_stub;
template_size = (sizeof (arm_pic_long_branch_stub) / sizeof (bfd_vma)) * 4;
{
case arm_stub_long_branch:
_bfd_final_link_relocate (elf32_arm_howto_from_type (R_ARM_ABS32),
- stub_bfd, stub_sec, stub_sec->contents + 4,
- stub_entry->stub_offset, sym_value, 0);
+ stub_bfd, stub_sec, stub_sec->contents,
+ stub_entry->stub_offset + 4, sym_value, 0);
break;
case arm_thumb_v4t_stub_long_branch:
_bfd_final_link_relocate (elf32_arm_howto_from_type (R_ARM_ABS32),
- stub_bfd, stub_sec, stub_sec->contents + 8,
- stub_entry->stub_offset, sym_value, 0);
+ stub_bfd, stub_sec, stub_sec->contents,
+ stub_entry->stub_offset + 8, sym_value, 0);
break;
case arm_thumb_thumb_stub_long_branch:
_bfd_final_link_relocate (elf32_arm_howto_from_type (R_ARM_ABS32),
- stub_bfd, stub_sec, stub_sec->contents + 12,
- stub_entry->stub_offset, sym_value, 0);
+ stub_bfd, stub_sec, stub_sec->contents,
+ stub_entry->stub_offset + 12, sym_value, 0);
break;
case arm_thumb_arm_v4t_stub_long_branch:
_bfd_final_link_relocate (elf32_arm_howto_from_type (R_ARM_ABS32),
- stub_bfd, stub_sec, stub_sec->contents + 20,
- stub_entry->stub_offset, sym_value, 0);
+ stub_bfd, stub_sec, stub_sec->contents,
+ stub_entry->stub_offset + 16, sym_value, 0);
break;
+ case arm_thumb_arm_v4t_stub_short_branch:
+ {
+ long int rel_offset;
+ static const insn32 t2a3_b_insn = 0xea000000;
+
+ rel_offset = sym_value - (stub_addr + 8 + 4);
+
+ put_arm_insn (globals, stub_bfd,
+ (bfd_vma) t2a3_b_insn | ((rel_offset >> 2) & 0x00FFFFFF),
+ loc + 4);
+ }
+ break;
+
case arm_stub_pic_long_branch:
/* We want the value relative to the address 8 bytes from the
start of the stub. */
- sym_value -= stub_addr + 8;
-
- _bfd_final_link_relocate (elf32_arm_howto_from_type (R_ARM_ABS32),
- stub_bfd, stub_sec, stub_sec->contents + 8,
- stub_entry->stub_offset, sym_value, 0);
+ _bfd_final_link_relocate (elf32_arm_howto_from_type (R_ARM_REL32),
+ stub_bfd, stub_sec, stub_sec->contents,
+ stub_entry->stub_offset + 8, sym_value, 0);
break;
default:
break;
template = arm_thumb_arm_v4t_long_branch_stub;
template_size = (sizeof (arm_thumb_arm_v4t_long_branch_stub) / sizeof (bfd_vma)) * 4;
break;
+ case arm_thumb_arm_v4t_stub_short_branch:
+ template = arm_thumb_arm_v4t_short_branch_stub;
+ template_size = (sizeof(arm_thumb_arm_v4t_short_branch_stub) / sizeof (bfd_vma)) * 4;
+ break;
case arm_stub_pic_long_branch:
template = arm_pic_long_branch_stub;
template_size = (sizeof (arm_pic_long_branch_stub) / sizeof (bfd_vma)) * 4;
bfd_vma sym_value;
bfd_vma destination;
struct elf32_arm_link_hash_entry *hash;
+ const char *sym_name;
char *stub_name;
const asection *id_sec;
unsigned char st_type;
sym_value = 0;
destination = 0;
hash = NULL;
+ sym_name = NULL;
if (r_indx < symtab_hdr->sh_info)
{
/* It's a local symbol. */
+ sym_sec->output_offset
+ sym_sec->output_section->vma);
st_type = ELF_ST_TYPE (sym->st_info);
+ sym_name
+ = bfd_elf_string_from_elf_section (input_bfd,
+ symtab_hdr->sh_link,
+ sym->st_name);
}
else
{
goto error_ret_free_internal;
}
st_type = ELF_ST_TYPE (hash->root.type);
+ sym_name = hash->root.root.root.string;
}
/* Determine what (if any) linker stub is needed. */
stub_type = arm_type_of_stub (info, section, irela, st_type,
- hash, destination);
+ hash, destination, sym_sec,
+ input_bfd, sym_name);
if (stub_type == arm_stub_none)
continue;
continue;
}
- stub_entry = elf32_arm_add_stub (stub_name, section, htab, info, stub_type);
+ stub_entry = elf32_arm_add_stub (stub_name, section, htab);
if (stub_entry == NULL)
{
free (stub_name);
stub_entry->stub_type = stub_type;
stub_entry->h = hash;
stub_entry->st_type = st_type;
+
+ if (sym_name == NULL)
+ sym_name = "unnamed";
+ stub_entry->output_name
+ = bfd_alloc (htab->stub_bfd,
+ sizeof (THUMB2ARM_GLUE_ENTRY_NAME)
+ + strlen (sym_name));
+ if (stub_entry->output_name == NULL)
+ {
+ free (stub_name);
+ goto error_ret_free_internal;
+ }
+
+ /* For historical reasons, use the existing names for
+ ARM-to-Thumb and Thumb-to-ARM stubs. */
+ if (r_type == (unsigned int) R_ARM_THM_CALL
+ && st_type != STT_ARM_TFUNC)
+ sprintf (stub_entry->output_name, THUMB2ARM_GLUE_ENTRY_NAME,
+ sym_name);
+ else if (r_type == (unsigned int) R_ARM_CALL
+ && st_type == STT_ARM_TFUNC)
+ sprintf (stub_entry->output_name, ARM2THUMB_GLUE_ENTRY_NAME,
+ sym_name);
+ else
+ sprintf (stub_entry->output_name, STUB_ENTRY_NAME,
+ sym_name);
+
stub_changed = TRUE;
}
{
bfd_size_type size;
- /* Ignore non-stub sections */
+ /* Ignore non-stub sections. */
if (!strstr (stub_sec->name, STUB_SUFFIX))
continue;
add r12, r12, pc
bx r12
__func_offset:
- .word func - .
- */
+ .word func - . */
#define ARM2THUMB_STATIC_GLUE_SIZE 12
static const insn32 a2t1_ldr_insn = 0xe59fc000;
/* Thumb->ARM: Thumb->(non-interworking aware) ARM
- .thumb .thumb
- .align 2 .align 2
- __func_from_thumb: __func_from_thumb:
- bx pc push {r6, lr}
- nop ldr r6, __func_addr
- .arm mov lr, pc
- __func_change_to_arm: bx r6
- b func .arm
- __func_back_to_thumb:
- ldmia r13! {r6, lr}
- bx lr
- __func_addr:
- .word func */
+ .thumb .thumb
+ .align 2 .align 2
+ __func_from_thumb: __func_from_thumb:
+ bx pc push {r6, lr}
+ nop ldr r6, __func_addr
+ .arm mov lr, pc
+ b func bx r6
+ .arm
+ ;; back_to_thumb
+ ldmia r13! {r6, lr}
+ bx lr
+ __func_addr:
+ .word func */
#define THUMB2ARM_GLUE_SIZE 8
static const insn16 t2a1_bx_pc_insn = 0x4778;
static const insn32 armbx3_bx_insn = 0xe12fff10;
#ifndef ELFARM_NABI_C_INCLUDED
-bfd_boolean
-bfd_elf32_arm_allocate_interworking_sections (struct bfd_link_info * info)
+static void
+arm_allocate_glue_section_space (bfd * abfd, bfd_size_type size, const char * name)
{
asection * s;
- bfd_byte * foo;
- struct elf32_arm_link_hash_table * globals;
-
- globals = elf32_arm_hash_table (info);
+ bfd_byte * contents;
- BFD_ASSERT (globals != NULL);
-
- if (globals->arm_glue_size != 0)
- {
- BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
-
- s = bfd_get_section_by_name (globals->bfd_of_glue_owner,
- ARM2THUMB_GLUE_SECTION_NAME);
-
- BFD_ASSERT (s != NULL);
-
- foo = bfd_alloc (globals->bfd_of_glue_owner, globals->arm_glue_size);
-
- BFD_ASSERT (s->size == globals->arm_glue_size);
- s->contents = foo;
- }
-
- if (globals->thumb_glue_size != 0)
- {
- BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
+ if (size == 0)
+ return;
- s = bfd_get_section_by_name
- (globals->bfd_of_glue_owner, THUMB2ARM_GLUE_SECTION_NAME);
+ BFD_ASSERT (abfd != NULL);
- BFD_ASSERT (s != NULL);
+ s = bfd_get_section_by_name (abfd, name);
+ BFD_ASSERT (s != NULL);
- foo = bfd_alloc (globals->bfd_of_glue_owner, globals->thumb_glue_size);
+ contents = bfd_alloc (abfd, size);
- BFD_ASSERT (s->size == globals->thumb_glue_size);
- s->contents = foo;
- }
-
- if (globals->vfp11_erratum_glue_size != 0)
- {
- BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
+ BFD_ASSERT (s->size == size);
+ s->contents = contents;
+}
- s = bfd_get_section_by_name
- (globals->bfd_of_glue_owner, VFP11_ERRATUM_VENEER_SECTION_NAME);
+bfd_boolean
+bfd_elf32_arm_allocate_interworking_sections (struct bfd_link_info * info)
+{
+ struct elf32_arm_link_hash_table * globals;
- BFD_ASSERT (s != NULL);
+ globals = elf32_arm_hash_table (info);
+ BFD_ASSERT (globals != NULL);
- foo = bfd_alloc (globals->bfd_of_glue_owner,
- globals->vfp11_erratum_glue_size);
+ arm_allocate_glue_section_space (globals->bfd_of_glue_owner,
+ globals->arm_glue_size,
+ ARM2THUMB_GLUE_SECTION_NAME);
- BFD_ASSERT (s->size == globals->vfp11_erratum_glue_size);
- s->contents = foo;
- }
+ arm_allocate_glue_section_space (globals->bfd_of_glue_owner,
+ globals->thumb_glue_size,
+ THUMB2ARM_GLUE_SECTION_NAME);
- if (globals->bx_glue_size != 0)
- {
- BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
+ arm_allocate_glue_section_space (globals->bfd_of_glue_owner,
+ globals->vfp11_erratum_glue_size,
+ VFP11_ERRATUM_VENEER_SECTION_NAME);
- s = bfd_get_section_by_name (globals->bfd_of_glue_owner,
+ arm_allocate_glue_section_space (globals->bfd_of_glue_owner,
+ globals->bx_glue_size,
ARM_BX_GLUE_SECTION_NAME);
- BFD_ASSERT (s != NULL);
-
- foo = bfd_alloc (globals->bfd_of_glue_owner, globals->bx_glue_size);
-
- BFD_ASSERT (s->size == globals->bx_glue_size);
- s->contents = foo;
- }
-
return TRUE;
}
/* The only trick here is using hash_table->arm_glue_size as the value.
Even though the section isn't allocated yet, this is where we will be
- putting it. */
+ putting it. The +1 on the value marks that the stub has not been
+ output yet - not that it is a Thumb function. */
bh = NULL;
val = globals->arm_glue_size + 1;
_bfd_generic_link_add_one_symbol (link_info, globals->bfd_of_glue_owner,
return;
}
+ /* The only trick here is using hash_table->thumb_glue_size as the value.
+ Even though the section isn't allocated yet, this is where we will be
+ putting it. The +1 on the value marks that the stub has not been
+ output yet - not that it is a Thumb function. */
bh = NULL;
val = hash_table->thumb_glue_size + 1;
_bfd_generic_link_add_one_symbol (link_info, hash_table->bfd_of_glue_owner,
s->size += THUMB2ARM_GLUE_SIZE;
hash_table->thumb_glue_size += THUMB2ARM_GLUE_SIZE;
-
- return;
}
return val;
}
+/* Note: we do not include the flag SEC_LINKER_CREATED, as that
+ would prevent elf_link_input_bfd() from processing the contents
+ of the section. */
+#define ARM_GLUE_SECTION_FLAGS \
+ (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_CODE | SEC_READONLY)
+
+/* Create a fake section for use by the ARM backend of the linker. */
+
+static bfd_boolean
+arm_make_glue_section (bfd * abfd, const char * name)
+{
+ asection * sec;
+
+ sec = bfd_get_section_by_name (abfd, name);
+ if (sec != NULL)
+ /* Already made. */
+ return TRUE;
+
+ sec = bfd_make_section_with_flags (abfd, name, ARM_GLUE_SECTION_FLAGS);
+
+ if (sec == NULL
+ || !bfd_set_section_alignment (abfd, sec, 2))
+ return FALSE;
+
+ /* Set the gc mark to prevent the section from being removed by garbage
+ collection, despite the fact that no relocs refer to this section. */
+ sec->gc_mark = 1;
+
+ return TRUE;
+}
+
/* Add the glue sections to ABFD. This function is called from the
linker scripts in ld/emultempl/{armelf}.em. */
bfd_elf32_arm_add_glue_sections_to_bfd (bfd *abfd,
struct bfd_link_info *info)
{
- flagword flags;
- asection *sec;
-
/* If we are only performing a partial
link do not bother adding the glue. */
if (info->relocatable)
return TRUE;
- /* linker stubs don't need glue */
+ /* Linker stubs don't need glue. */
if (!strcmp (abfd->filename, "linker stubs"))
return TRUE;
- sec = bfd_get_section_by_name (abfd, ARM2THUMB_GLUE_SECTION_NAME);
-
- if (sec == NULL)
- {
- /* Note: we do not include the flag SEC_LINKER_CREATED, as this
- will prevent elf_link_input_bfd() from processing the contents
- of this section. */
- flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
- | SEC_CODE | SEC_READONLY);
-
- sec = bfd_make_section_with_flags (abfd,
- ARM2THUMB_GLUE_SECTION_NAME,
- flags);
-
- if (sec == NULL
- || !bfd_set_section_alignment (abfd, sec, 2))
- return FALSE;
-
- /* Set the gc mark to prevent the section from being removed by garbage
- collection, despite the fact that no relocs refer to this section. */
- sec->gc_mark = 1;
- }
-
- sec = bfd_get_section_by_name (abfd, THUMB2ARM_GLUE_SECTION_NAME);
-
- if (sec == NULL)
- {
- flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
- | SEC_CODE | SEC_READONLY);
-
- sec = bfd_make_section_with_flags (abfd,
- THUMB2ARM_GLUE_SECTION_NAME,
- flags);
-
- if (sec == NULL
- || !bfd_set_section_alignment (abfd, sec, 2))
- return FALSE;
-
- sec->gc_mark = 1;
- }
-
- sec = bfd_get_section_by_name (abfd, VFP11_ERRATUM_VENEER_SECTION_NAME);
-
- if (sec == NULL)
- {
- flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
- | SEC_CODE | SEC_READONLY);
-
- sec = bfd_make_section_with_flags (abfd,
- VFP11_ERRATUM_VENEER_SECTION_NAME,
- flags);
-
- if (sec == NULL
- || !bfd_set_section_alignment (abfd, sec, 2))
- return FALSE;
-
- sec->gc_mark = 1;
- }
-
- sec = bfd_get_section_by_name (abfd, ARM_BX_GLUE_SECTION_NAME);
-
- if (sec == NULL)
- {
- flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
- | SEC_CODE | SEC_READONLY);
-
- sec = bfd_make_section_with_flags (abfd,
- ARM_BX_GLUE_SECTION_NAME,
- flags);
-
- if (sec == NULL
- || !bfd_set_section_alignment (abfd, sec, 2))
- return FALSE;
-
- sec->gc_mark = 1;
- }
-
- return TRUE;
+ return arm_make_glue_section (abfd, ARM2THUMB_GLUE_SECTION_NAME)
+ && arm_make_glue_section (abfd, THUMB2ARM_GLUE_SECTION_NAME)
+ && arm_make_glue_section (abfd, VFP11_ERRATUM_VENEER_SECTION_NAME)
+ && arm_make_glue_section (abfd, ARM_BX_GLUE_SECTION_NAME);
}
/* Select a BFD to be used to hold the sections used by the glue code.
This function is called from the linker scripts in ld/emultempl/
- {armelf/pe}.em */
+ {armelf/pe}.em. */
bfd_boolean
bfd_elf32_arm_get_bfd_for_interworking (bfd *abfd, struct bfd_link_info *info)
Elf_Internal_Shdr *hdr;
unsigned int i, localsyms;
+ /* PR 7093: Make sure that we are dealing with an arm elf binary. */
+ if (! is_arm_elf (abfd))
+ return;
+
if ((abfd->flags & DYNAMIC) != 0)
return;
int fix_v4bx,
int use_blx,
bfd_arm_vfp11_fix vfp11_fix,
- int no_enum_warn, int pic_veneer)
+ int no_enum_warn, int no_wchar_warn,
+ int pic_veneer)
{
struct elf32_arm_link_hash_table *globals;
BFD_ASSERT (is_arm_elf (output_bfd));
elf_arm_tdata (output_bfd)->no_enum_size_warning = no_enum_warn;
+ elf_arm_tdata (output_bfd)->no_wchar_size_warning = no_wchar_warn;
}
/* Replace the target offset of a Thumb bl or b.w instruction. */
bfd * output_bfd,
asection * sym_sec,
bfd_vma val,
- asection *s,
- char **error_message)
+ asection * s,
+ char ** error_message)
{
bfd_vma my_offset;
long int ret_offset;
/* It's a thumb address. Add the low order bit. */
bfd_put_32 (output_bfd, val | a2t3_func_addr_insn,
s->contents + my_offset + 8);
+
+ my_offset += 12;
}
}
val = eh->export_glue->root.u.def.value + sec->output_offset
+ sec->output_section->vma;
+
myh = elf32_arm_create_thumb_stub (info, h->root.root.string,
h->root.u.def.section->owner,
globals->obfd, sec, val, s,
{
struct elf32_arm_link_hash_table * globals;
- if (!link_info)
+ if (link_info == NULL)
+ /* Ignore this if we are not called by the ELF backend linker. */
return;
globals = elf32_arm_hash_table (link_info);
/* Some relocations map to different relocations depending on the
target. Return the real relocation. */
+
static int
arm_real_reloc_type (struct elf32_arm_link_hash_table * globals,
int r_type)
int sym_flags,
struct elf_link_hash_entry * h,
bfd_boolean * unresolved_reloc_p,
- char **error_message)
+ char ** error_message)
{
unsigned long r_type = howto->type;
unsigned long r_symndx;
if (sreloc == NULL)
{
- const char * name;
+ sreloc = _bfd_elf_get_dynamic_reloc_section (input_bfd, input_section,
+ ! globals->use_rel);
- name = (bfd_elf_string_from_elf_section
- (input_bfd,
- elf_elfheader (input_bfd)->e_shstrndx,
- elf_section_data (input_section)->rel_hdr.sh_name));
- if (name == NULL)
+ if (sreloc == NULL)
return bfd_reloc_notsupported;
-
- BFD_ASSERT (reloc_section_p (globals, name, input_section));
-
- sreloc = bfd_get_section_by_name (dynobj, name);
- BFD_ASSERT (sreloc != NULL);
}
skip = FALSE;
case R_ARM_XPC25: /* Arm BLX instruction. */
case R_ARM_CALL:
case R_ARM_JUMP24:
- case R_ARM_PC24: /* Arm B/BL instruction */
+ case R_ARM_PC24: /* Arm B/BL instruction. */
case R_ARM_PLT32:
{
bfd_vma from;
}
/* Check if a stub has to be inserted because the
- destination is too far or we are changing mode */
+ destination is too far or we are changing mode. */
if (r_type == R_ARM_CALL)
{
if (branch_offset > ARM_MAX_FWD_BRANCH_OFFSET
{
/* Select the correct instruction (BL or BLX). */
/* Only if we are not handling a BL to a stub. In this
- case, mode switching is performed by the stub. */
+ case, mode switching is performed by the stub. */
if (sym_flags == STT_ARM_TFUNC && !stub_entry)
value |= (1 << 28);
else
value += signed_addend;
if (! h || h->root.type != bfd_link_hash_undefweak)
{
- /* Check for overflow */
+ /* Check for overflow. */
if ((value ^ (value >> 1)) & (1 << 30))
return bfd_reloc_overflow;
}
int thumb2 = using_thumb2 (globals);
/* A branch to an undefined weak symbol is turned into a jump to
- the next instruction. */
- if (h && h->root.type == bfd_link_hash_undefweak)
+ 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))
{
bfd_put_16 (input_bfd, 0xe000, hit_data);
bfd_put_16 (input_bfd, 0xbf00, hit_data + 2);
/* Convert BL to BLX. */
lower_insn = (lower_insn & ~0x1000) | 0x0800;
}
- else if (elf32_thumb_to_arm_stub
- (info, sym_name, input_bfd, output_bfd, input_section,
- hit_data, sym_sec, rel->r_offset, signed_addend, value,
- error_message))
- return bfd_reloc_ok;
- else
- return bfd_reloc_dangerous;
+ else if (r_type != R_ARM_THM_CALL)
+ {
+ if (elf32_thumb_to_arm_stub
+ (info, sym_name, input_bfd, output_bfd, input_section,
+ hit_data, sym_sec, rel->r_offset, signed_addend, value,
+ error_message))
+ return bfd_reloc_ok;
+ else
+ return bfd_reloc_dangerous;
+ }
}
else if (sym_flags == STT_ARM_TFUNC && globals->use_blx
&& r_type == R_ARM_THM_CALL)
if (r_type == R_ARM_THM_CALL)
{
/* Check if a stub has to be inserted because the destination
- is too far. */
+ is too far. */
bfd_vma from;
bfd_signed_vma branch_offset;
struct elf32_arm_stub_hash_entry *stub_entry = NULL;
||
(thumb2
&& (branch_offset > THM2_MAX_FWD_BRANCH_OFFSET
- || (branch_offset < THM2_MAX_BWD_BRANCH_OFFSET))))
+ || (branch_offset < THM2_MAX_BWD_BRANCH_OFFSET)))
+ || ((sym_flags != STT_ARM_TFUNC) && !globals->use_blx))
{
/* The target is out of reach or we are changing modes, so
redirect the branch to the local stub for this
+ stub_entry->stub_sec->output_offset
+ stub_entry->stub_sec->output_section->vma);
- /* This call becomes a call to Arm for sure. Force BLX. */
- lower_insn = (lower_insn & ~0x1000) | 0x0800;
+ /* If this call becomes a call to Arm, force BLX. */
+ if (globals->use_blx)
+ {
+ if ((stub_entry
+ && !arm_stub_is_thumb (stub_entry->stub_type))
+ || (sym_flags != STT_ARM_TFUNC))
+ lower_insn = (lower_insn & ~0x1000) | 0x0800;
+ }
}
}
default:
error_message = _("unknown error");
- /* fall through */
+ /* Fall through. */
common_error:
BFD_ASSERT (error_message != NULL);
{
if (tag == Tag_compatibility)
return 3;
+ else if (tag == Tag_nodefaults)
+ return 5;
else if (tag == 4 || tag == 5)
return 2;
else if (tag < 32)
return (tag & 1) != 0 ? 2 : 1;
}
+/* Read the architecture from the Tag_also_compatible_with attribute, if any.
+ Returns -1 if no architecture could be read. */
+
+static int
+get_secondary_compatible_arch (bfd *abfd)
+{
+ obj_attribute *attr =
+ &elf_known_obj_attributes_proc (abfd)[Tag_also_compatible_with];
+
+ /* 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[0] == Tag_CPU_arch
+ && (attr->s[1] & 128) != 128
+ && attr->s[2] == 0)
+ return attr->s[1];
+
+ /* This tag is "safely ignorable", so don't complain if it looks funny. */
+ return -1;
+}
+
+/* Set, or unset, the architecture of the Tag_also_compatible_with attribute.
+ The tag is removed if ARCH is -1. */
+
+static void
+set_secondary_compatible_arch (bfd *abfd, int arch)
+{
+ obj_attribute *attr =
+ &elf_known_obj_attributes_proc (abfd)[Tag_also_compatible_with];
+
+ if (arch == -1)
+ {
+ attr->s = NULL;
+ return;
+ }
+
+ /* 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[0] = Tag_CPU_arch;
+ attr->s[1] = arch;
+ attr->s[2] = '\0';
+}
+
+/* Combine two values for Tag_CPU_arch, taking secondary compatibility tags
+ into account. */
+
+static int
+tag_cpu_arch_combine (bfd *ibfd, int oldtag, int *secondary_compat_out,
+ int newtag, int secondary_compat)
+{
+#define T(X) TAG_CPU_ARCH_##X
+ int tagl, tagh, result;
+ const int v6t2[] =
+ {
+ T(V6T2), /* PRE_V4. */
+ T(V6T2), /* V4. */
+ T(V6T2), /* V4T. */
+ T(V6T2), /* V5T. */
+ T(V6T2), /* V5TE. */
+ T(V6T2), /* V5TEJ. */
+ T(V6T2), /* V6. */
+ T(V7), /* V6KZ. */
+ T(V6T2) /* V6T2. */
+ };
+ const int v6k[] =
+ {
+ T(V6K), /* PRE_V4. */
+ T(V6K), /* V4. */
+ T(V6K), /* V4T. */
+ T(V6K), /* V5T. */
+ T(V6K), /* V5TE. */
+ T(V6K), /* V5TEJ. */
+ T(V6K), /* V6. */
+ T(V6KZ), /* V6KZ. */
+ T(V7), /* V6T2. */
+ T(V6K) /* V6K. */
+ };
+ const int v7[] =
+ {
+ T(V7), /* PRE_V4. */
+ T(V7), /* V4. */
+ T(V7), /* V4T. */
+ T(V7), /* V5T. */
+ T(V7), /* V5TE. */
+ T(V7), /* V5TEJ. */
+ T(V7), /* V6. */
+ T(V7), /* V6KZ. */
+ T(V7), /* V6T2. */
+ T(V7), /* V6K. */
+ T(V7) /* V7. */
+ };
+ const int v6_m[] =
+ {
+ -1, /* PRE_V4. */
+ -1, /* V4. */
+ T(V6K), /* V4T. */
+ T(V6K), /* V5T. */
+ T(V6K), /* V5TE. */
+ T(V6K), /* V5TEJ. */
+ T(V6K), /* V6. */
+ T(V6KZ), /* V6KZ. */
+ T(V7), /* V6T2. */
+ T(V6K), /* V6K. */
+ T(V7), /* V7. */
+ T(V6_M) /* V6_M. */
+ };
+ const int v6s_m[] =
+ {
+ -1, /* PRE_V4. */
+ -1, /* V4. */
+ T(V6K), /* V4T. */
+ T(V6K), /* V5T. */
+ T(V6K), /* V5TE. */
+ T(V6K), /* V5TEJ. */
+ T(V6K), /* V6. */
+ T(V6KZ), /* V6KZ. */
+ T(V7), /* V6T2. */
+ T(V6K), /* V6K. */
+ T(V7), /* V7. */
+ T(V6S_M), /* V6_M. */
+ T(V6S_M) /* V6S_M. */
+ };
+ const int v4t_plus_v6_m[] =
+ {
+ -1, /* PRE_V4. */
+ -1, /* V4. */
+ T(V4T), /* V4T. */
+ T(V5T), /* V5T. */
+ T(V5TE), /* V5TE. */
+ T(V5TEJ), /* V5TEJ. */
+ T(V6), /* V6. */
+ T(V6KZ), /* V6KZ. */
+ T(V6T2), /* V6T2. */
+ T(V6K), /* V6K. */
+ T(V7), /* V7. */
+ T(V6_M), /* V6_M. */
+ T(V6S_M), /* V6S_M. */
+ T(V4T_PLUS_V6_M) /* V4T plus V6_M. */
+ };
+ const int *comb[] =
+ {
+ v6t2,
+ v6k,
+ v7,
+ v6_m,
+ v6s_m,
+ /* Pseudo-architecture. */
+ v4t_plus_v6_m
+ };
+
+ /* Check we've not got a higher architecture than we know about. */
+
+ if (oldtag >= MAX_TAG_CPU_ARCH || newtag >= MAX_TAG_CPU_ARCH)
+ {
+ _bfd_error_handler (_("ERROR: %B: Unknown CPU architecture"), ibfd);
+ return -1;
+ }
+
+ /* Override old tag if we have a Tag_also_compatible_with on the output. */
+
+ if ((oldtag == T(V6_M) && *secondary_compat_out == T(V4T))
+ || (oldtag == T(V4T) && *secondary_compat_out == T(V6_M)))
+ oldtag = T(V4T_PLUS_V6_M);
+
+ /* And override the new tag if we have a Tag_also_compatible_with on the
+ input. */
+
+ if ((newtag == T(V6_M) && secondary_compat == T(V4T))
+ || (newtag == T(V4T) && secondary_compat == T(V6_M)))
+ newtag = T(V4T_PLUS_V6_M);
+
+ tagl = (oldtag < newtag) ? oldtag : newtag;
+ result = tagh = (oldtag > newtag) ? oldtag : newtag;
+
+ /* Architectures before V6KZ add features monotonically. */
+ if (tagh <= TAG_CPU_ARCH_V6KZ)
+ return result;
+
+ result = comb[tagh - T(V6T2)][tagl];
+
+ /* Use Tag_CPU_arch == V4T and Tag_also_compatible_with (Tag_CPU_arch V6_M)
+ as the canonical version. */
+ if (result == T(V4T_PLUS_V6_M))
+ {
+ result = T(V4T);
+ *secondary_compat_out = T(V6_M);
+ }
+ else
+ *secondary_compat_out = -1;
+
+ if (result == -1)
+ {
+ _bfd_error_handler (_("ERROR: %B: Conflicting CPU architectures %d/%d"),
+ ibfd, oldtag, newtag);
+ return -1;
+ }
+
+ return result;
+#undef T
+}
+
/* Merge EABI object attributes from IBFD into OBFD. Raise an error if there
are conflicting attributes. */
obj_attribute *in_attr;
obj_attribute *out_attr;
obj_attribute_list *in_list;
+ obj_attribute_list *out_list;
+ obj_attribute_list **out_listp;
/* Some tags have 0 = don't care, 1 = strong requirement,
2 = weak requirement. */
- static const int order_312[3] = {3, 1, 2};
+ static const int order_021[3] = {0, 2, 1};
/* For use with Tag_VFP_arch. */
static const int order_01243[5] = {0, 1, 2, 4, 3};
int i;
+ bfd_boolean result = TRUE;
if (!elf_known_obj_attributes_proc (obfd)[0].i)
{
/* This needs to happen before Tag_ABI_FP_number_model is merged. */
if (in_attr[Tag_ABI_VFP_args].i != out_attr[Tag_ABI_VFP_args].i)
{
- /* Ignore mismatches if teh object doesn't use floating point. */
+ /* Ignore mismatches if the object doesn't use floating point. */
if (out_attr[Tag_ABI_FP_number_model].i == 0)
out_attr[Tag_ABI_VFP_args].i = in_attr[Tag_ABI_VFP_args].i;
else if (in_attr[Tag_ABI_FP_number_model].i != 0)
_bfd_error_handler
(_("ERROR: %B uses VFP register arguments, %B does not"),
ibfd, obfd);
- return FALSE;
+ result = FALSE;
}
}
{
case Tag_CPU_raw_name:
case Tag_CPU_name:
- /* Use whichever has the greatest architecture requirements. We
- won't necessarily have both the above tags, so make sure input
- name is non-NULL. */
- if (in_attr[Tag_CPU_arch].i > out_attr[Tag_CPU_arch].i
- && in_attr[i].s)
- out_attr[i].s = _bfd_elf_attr_strdup (obfd, in_attr[i].s);
+ /* These are merged after Tag_CPU_arch. */
break;
case Tag_ABI_optimization_goals:
break;
case Tag_CPU_arch:
+ {
+ int secondary_compat = -1, secondary_compat_out = -1;
+ unsigned int saved_out_attr = out_attr[i].i;
+ static const char *name_table[] = {
+ /* These aren't real CPU names, but we can't guess
+ that from the architecture version alone. */
+ "Pre v4",
+ "ARM v4",
+ "ARM v4T",
+ "ARM v5T",
+ "ARM v5TE",
+ "ARM v5TEJ",
+ "ARM v6",
+ "ARM v6KZ",
+ "ARM v6T2",
+ "ARM v6K",
+ "ARM v7",
+ "ARM v6-M",
+ "ARM v6S-M"
+ };
+
+ /* Merge Tag_CPU_arch and Tag_also_compatible_with. */
+ secondary_compat = get_secondary_compatible_arch (ibfd);
+ secondary_compat_out = get_secondary_compatible_arch (obfd);
+ out_attr[i].i = tag_cpu_arch_combine (ibfd, out_attr[i].i,
+ &secondary_compat_out,
+ in_attr[i].i,
+ secondary_compat);
+ set_secondary_compatible_arch (obfd, secondary_compat_out);
+
+ /* Merge Tag_CPU_name and Tag_CPU_raw_name. */
+ if (out_attr[i].i == saved_out_attr)
+ ; /* Leave the names alone. */
+ else if (out_attr[i].i == in_attr[i].i)
+ {
+ /* The output architecture has been changed to match the
+ input architecture. Use the input names. */
+ out_attr[Tag_CPU_name].s = in_attr[Tag_CPU_name].s
+ ? _bfd_elf_attr_strdup (obfd, in_attr[Tag_CPU_name].s)
+ : NULL;
+ out_attr[Tag_CPU_raw_name].s = in_attr[Tag_CPU_raw_name].s
+ ? _bfd_elf_attr_strdup (obfd, in_attr[Tag_CPU_raw_name].s)
+ : NULL;
+ }
+ else
+ {
+ out_attr[Tag_CPU_name].s = NULL;
+ out_attr[Tag_CPU_raw_name].s = NULL;
+ }
+
+ /* If we still don't have a value for Tag_CPU_name,
+ make one up now. Tag_CPU_raw_name remains blank. */
+ if (out_attr[Tag_CPU_name].s == NULL
+ && out_attr[i].i < ARRAY_SIZE (name_table))
+ out_attr[Tag_CPU_name].s =
+ _bfd_elf_attr_strdup (obfd, name_table[out_attr[i].i]);
+ }
+ break;
+
case Tag_ARM_ISA_use:
case Tag_THUMB_ISA_use:
case Tag_WMMX_arch:
- case Tag_NEON_arch:
- /* ??? Do NEON and WMMX conflict? */
+ case Tag_Advanced_SIMD_arch:
+ /* ??? Do Advanced_SIMD (NEON) and WMMX conflict? */
case Tag_ABI_FP_rounding:
- case Tag_ABI_FP_denormal:
case Tag_ABI_FP_exceptions:
case Tag_ABI_FP_user_exceptions:
case Tag_ABI_FP_number_model:
- case Tag_ABI_align8_preserved:
- case Tag_ABI_HardFP_use:
+ case Tag_VFP_HP_extension:
+ case Tag_CPU_unaligned_access:
+ case Tag_T2EE_use:
+ case Tag_Virtualization_use:
+ case Tag_MPextension_use:
/* Use the largest value specified. */
if (in_attr[i].i > out_attr[i].i)
out_attr[i].i = in_attr[i].i;
break;
- case Tag_CPU_arch_profile:
- /* Warn if conflicting architecture profiles used. */
- if (out_attr[i].i && in_attr[i].i && in_attr[i].i != out_attr[i].i)
+ case Tag_ABI_align8_preserved:
+ case Tag_ABI_PCS_RO_data:
+ /* Use the smallest value specified. */
+ if (in_attr[i].i < out_attr[i].i)
+ out_attr[i].i = in_attr[i].i;
+ break;
+
+ case Tag_ABI_align8_needed:
+ if ((in_attr[i].i > 0 || out_attr[i].i > 0)
+ && (in_attr[Tag_ABI_align8_preserved].i == 0
+ || out_attr[Tag_ABI_align8_preserved].i == 0))
{
+ /* This error message should be enabled once all non-conformant
+ binaries in the toolchain have had the attributes set
+ properly.
_bfd_error_handler
- (_("ERROR: %B: Conflicting architecture profiles %c/%c"),
- ibfd, in_attr[i].i, out_attr[i].i);
- return FALSE;
+ (_("ERROR: %B: 8-byte data alignment conflicts with %B"),
+ obfd, ibfd);
+ result = FALSE; */
}
- if (in_attr[i].i)
+ /* Fall through. */
+ case Tag_ABI_FP_denormal:
+ case Tag_ABI_PCS_GOT_use:
+ /* Use the "greatest" from the sequence 0, 2, 1, or the largest
+ value if greater than 2 (for future-proofing). */
+ if ((in_attr[i].i > 2 && in_attr[i].i > out_attr[i].i)
+ || (in_attr[i].i <= 2 && out_attr[i].i <= 2
+ && order_021[in_attr[i].i] > order_021[out_attr[i].i]))
out_attr[i].i = in_attr[i].i;
break;
+
+
+ case Tag_CPU_arch_profile:
+ if (out_attr[i].i != in_attr[i].i)
+ {
+ /* 0 will merge with anything.
+ 'A' and 'S' merge to 'A'.
+ 'R' and 'S' merge to 'R'.
+ 'M' and 'A|R|S' is an error. */
+ if (out_attr[i].i == 0
+ || (out_attr[i].i == 'S'
+ && (in_attr[i].i == 'A' || in_attr[i].i == 'R')))
+ out_attr[i].i = in_attr[i].i;
+ else if (in_attr[i].i == 0
+ || (in_attr[i].i == 'S'
+ && (out_attr[i].i == 'A' || out_attr[i].i == 'R')))
+ ; /* Do nothing. */
+ else
+ {
+ _bfd_error_handler
+ (_("ERROR: %B: Conflicting architecture profiles %c/%c"),
+ ibfd,
+ in_attr[i].i ? in_attr[i].i : '0',
+ out_attr[i].i ? out_attr[i].i : '0');
+ result = FALSE;
+ }
+ }
+ break;
case Tag_VFP_arch:
- if (in_attr[i].i > 4 || out_attr[i].i > 4
- || order_01243[in_attr[i].i] > order_01243[out_attr[i].i])
+ /* Use the "greatest" from the sequence 0, 1, 2, 4, 3, or the
+ largest value if greater than 4 (for future-proofing). */
+ if ((in_attr[i].i > 4 && in_attr[i].i > out_attr[i].i)
+ || (in_attr[i].i <= 4 && out_attr[i].i <= 4
+ && order_01243[in_attr[i].i] > order_01243[out_attr[i].i]))
out_attr[i].i = in_attr[i].i;
break;
case Tag_PCS_config:
{
_bfd_error_handler
(_("ERROR: %B: Conflicting use of R9"), ibfd);
- return FALSE;
+ result = FALSE;
}
if (out_attr[i].i == AEABI_R9_unused)
out_attr[i].i = in_attr[i].i;
_bfd_error_handler
(_("ERROR: %B: SB relative addressing conflicts with use of R9"),
ibfd);
- return FALSE;
+ result = FALSE;
}
/* Use the smallest value specified. */
if (in_attr[i].i < out_attr[i].i)
out_attr[i].i = in_attr[i].i;
break;
- case Tag_ABI_PCS_RO_data:
- /* Use the smallest value specified. */
- if (in_attr[i].i < out_attr[i].i)
- out_attr[i].i = in_attr[i].i;
- break;
- case Tag_ABI_PCS_GOT_use:
- if (in_attr[i].i > 2 || out_attr[i].i > 2
- || order_312[in_attr[i].i] < order_312[out_attr[i].i])
- out_attr[i].i = in_attr[i].i;
- break;
case Tag_ABI_PCS_wchar_t:
- if (out_attr[i].i && in_attr[i].i && out_attr[i].i != in_attr[i].i)
+ if (out_attr[i].i && in_attr[i].i && out_attr[i].i != in_attr[i].i
+ && !elf_arm_tdata (obfd)->no_wchar_size_warning)
{
_bfd_error_handler
- (_("ERROR: %B: Conflicting definitions of wchar_t"), ibfd);
- return FALSE;
+ (_("warning: %B uses %u-byte wchar_t yet the output is to use %u-byte wchar_t; use of wchar_t values across objects may fail"),
+ ibfd, in_attr[i].i, out_attr[i].i);
}
- if (in_attr[i].i)
- out_attr[i].i = in_attr[i].i;
- break;
- case Tag_ABI_align8_needed:
- /* ??? Check against Tag_ABI_align8_preserved. */
- if (in_attr[i].i > 2 || out_attr[i].i > 2
- || order_312[in_attr[i].i] < order_312[out_attr[i].i])
+ else if (in_attr[i].i && !out_attr[i].i)
out_attr[i].i = in_attr[i].i;
break;
case Tag_ABI_enum_size:
&& out_attr[i].i != in_attr[i].i
&& !elf_arm_tdata (obfd)->no_enum_size_warning)
{
- const char *aeabi_enum_names[] =
+ static const char *aeabi_enum_names[] =
{ "", "variable-size", "32-bit", "" };
+ const char *in_name =
+ in_attr[i].i < ARRAY_SIZE(aeabi_enum_names)
+ ? aeabi_enum_names[in_attr[i].i]
+ : "<unknown>";
+ const char *out_name =
+ out_attr[i].i < ARRAY_SIZE(aeabi_enum_names)
+ ? aeabi_enum_names[out_attr[i].i]
+ : "<unknown>";
_bfd_error_handler
(_("warning: %B uses %s enums yet the output is to use %s enums; use of enum values across objects may fail"),
- ibfd, aeabi_enum_names[in_attr[i].i],
- aeabi_enum_names[out_attr[i].i]);
+ ibfd, in_name, out_name);
}
}
break;
_bfd_error_handler
(_("ERROR: %B uses iWMMXt register arguments, %B does not"),
ibfd, obfd);
- return FALSE;
+ result = FALSE;
}
break;
- default: /* All known attributes should be explicitly covered. */
- abort ();
- }
+ case Tag_compatibility:
+ /* Merged in target-independent code. */
+ break;
+ case Tag_ABI_HardFP_use:
+ /* 1 (SP) and 2 (DP) conflict, so combine to 3 (SP & DP). */
+ if ((in_attr[i].i == 1 && out_attr[i].i == 2)
+ || (in_attr[i].i == 2 && out_attr[i].i == 1))
+ out_attr[i].i = 3;
+ else if (in_attr[i].i > out_attr[i].i)
+ out_attr[i].i = in_attr[i].i;
+ break;
+ case Tag_ABI_FP_16bit_format:
+ if (in_attr[i].i != 0 && out_attr[i].i != 0)
+ {
+ if (in_attr[i].i != out_attr[i].i)
+ {
+ _bfd_error_handler
+ (_("ERROR: fp16 format mismatch between %B and %B"),
+ ibfd, obfd);
+ result = FALSE;
+ }
+ }
+ if (in_attr[i].i != 0)
+ out_attr[i].i = in_attr[i].i;
+ break;
- if (in_attr[i].type && !out_attr[i].type)
- switch (in_attr[i].type)
+ case Tag_nodefaults:
+ /* This tag is set if it exists, but the value is unused (and is
+ typically zero). We don't actually need to do anything here -
+ the merge happens automatically when the type flags are merged
+ below. */
+ break;
+ case Tag_also_compatible_with:
+ /* Already done in Tag_CPU_arch. */
+ break;
+ case Tag_conformance:
+ /* Keep the attribute if it matches. Throw it away otherwise.
+ No attribute means no claim to conform. */
+ if (!in_attr[i].s || !out_attr[i].s
+ || strcmp (in_attr[i].s, out_attr[i].s) != 0)
+ out_attr[i].s = NULL;
+ break;
+
+ default:
{
- case 1:
- if (out_attr[i].i)
- out_attr[i].type = 1;
- break;
+ bfd *err_bfd = NULL;
- case 2:
- if (out_attr[i].s)
- out_attr[i].type = 2;
- break;
+ /* The "known_obj_attributes" table does contain some undefined
+ attributes. Ensure that there are unused. */
+ if (out_attr[i].i != 0 || out_attr[i].s != NULL)
+ err_bfd = obfd;
+ else if (in_attr[i].i != 0 || in_attr[i].s != NULL)
+ err_bfd = ibfd;
- default:
- abort ();
+ if (err_bfd != NULL)
+ {
+ /* Attribute numbers >=64 (mod 128) can be safely ignored. */
+ if ((i & 127) < 64)
+ {
+ _bfd_error_handler
+ (_("%B: Unknown mandatory EABI object attribute %d"),
+ err_bfd, i);
+ bfd_set_error (bfd_error_bad_value);
+ result = FALSE;
+ }
+ else
+ {
+ _bfd_error_handler
+ (_("Warning: %B: Unknown EABI object attribute %d"),
+ err_bfd, i);
+ }
+ }
+
+ /* Only pass on attributes that match in both inputs. */
+ if (in_attr[i].i != out_attr[i].i
+ || in_attr[i].s != out_attr[i].s
+ || (in_attr[i].s != NULL && out_attr[i].s != NULL
+ && strcmp (in_attr[i].s, out_attr[i].s) != 0))
+ {
+ out_attr[i].i = 0;
+ out_attr[i].s = NULL;
+ }
}
+ }
+
+ /* If out_attr was copied from in_attr then it won't have a type yet. */
+ if (in_attr[i].type && !out_attr[i].type)
+ out_attr[i].type = in_attr[i].type;
}
/* Merge Tag_compatibility attributes and any common GNU ones. */
/* Check for any attributes not known on ARM. */
in_list = elf_other_obj_attributes_proc (ibfd);
- while (in_list && in_list->tag == Tag_compatibility)
- in_list = in_list->next;
+ out_listp = &elf_other_obj_attributes_proc (obfd);
+ out_list = *out_listp;
- for (; in_list; in_list = in_list->next)
+ for (; in_list || out_list; )
{
- if ((in_list->tag & 128) < 64)
+ bfd *err_bfd = NULL;
+ int err_tag = 0;
+
+ /* The tags for each list are in numerical order. */
+ /* If the tags are equal, then merge. */
+ if (out_list && (!in_list || in_list->tag > out_list->tag))
{
- _bfd_error_handler
- (_("Warning: %B: Unknown EABI object attribute %d"),
- ibfd, in_list->tag);
- break;
+ /* This attribute only exists in obfd. We can't merge, and we don't
+ know what the tag means, so delete it. */
+ err_bfd = obfd;
+ err_tag = out_list->tag;
+ *out_listp = out_list->next;
+ out_list = *out_listp;
+ }
+ else if (in_list && (!out_list || in_list->tag < out_list->tag))
+ {
+ /* This attribute only exists in ibfd. We can't merge, and we don't
+ know what the tag means, so ignore it. */
+ err_bfd = ibfd;
+ err_tag = in_list->tag;
+ in_list = in_list->next;
+ }
+ else /* The tags are equal. */
+ {
+ /* As present, all attributes in the list are unknown, and
+ therefore can't be merged meaningfully. */
+ err_bfd = obfd;
+ err_tag = out_list->tag;
+
+ /* Only pass on attributes that match in both inputs. */
+ if (in_list->attr.i != out_list->attr.i
+ || in_list->attr.s != out_list->attr.s
+ || (in_list->attr.s && out_list->attr.s
+ && strcmp (in_list->attr.s, out_list->attr.s) != 0))
+ {
+ /* No match. Delete the attribute. */
+ *out_listp = out_list->next;
+ out_list = *out_listp;
+ }
+ else
+ {
+ /* Matched. Keep the attribute and move to the next. */
+ out_list = out_list->next;
+ in_list = in_list->next;
+ }
+ }
+
+ if (err_bfd)
+ {
+ /* Attribute numbers >=64 (mod 128) can be safely ignored. */
+ if ((err_tag & 127) < 64)
+ {
+ _bfd_error_handler
+ (_("%B: Unknown mandatory EABI object attribute %d"),
+ err_bfd, err_tag);
+ bfd_set_error (bfd_error_bad_value);
+ result = FALSE;
+ }
+ else
+ {
+ _bfd_error_handler
+ (_("Warning: %B: Unknown EABI object attribute %d"),
+ err_bfd, err_tag);
+ }
}
}
- return TRUE;
+ return result;
}
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
elf32_arm_local_got_tls_type (abfd) [r_symndx] = tls_type;
}
}
- /* Fall through */
+ /* Fall through. */
case R_ARM_TLS_LDM32:
if (r_type == R_ARM_TLS_LDM32)
htab->tls_ldm_got.refcount++;
- /* Fall through */
+ /* Fall through. */
case R_ARM_GOTOFF32:
case R_ARM_GOTPC:
ldr __GOTT_INDEX__ offsets. */
if (!htab->vxworks_p)
break;
- /* Fall through */
+ /* Fall through. */
case R_ARM_PC24:
case R_ARM_PLT32:
/* When creating a shared object, we must copy these
reloc types into the output file. We create a reloc
section in dynobj and make room for this reloc. */
- if (sreloc == NULL)
+ if (sreloc == NULL)
{
- const char * name;
+ sreloc = _bfd_elf_make_dynamic_reloc_section
+ (sec, dynobj, 2, abfd, ! htab->use_rel);
- name = (bfd_elf_string_from_elf_section
- (abfd,
- elf_elfheader (abfd)->e_shstrndx,
- elf_section_data (sec)->rel_hdr.sh_name));
- if (name == NULL)
+ if (sreloc == NULL)
return FALSE;
- BFD_ASSERT (reloc_section_p (htab, name, sec));
-
- sreloc = bfd_get_section_by_name (dynobj, name);
- if (sreloc == NULL)
+ /* BPABI objects never have dynamic relocations mapped. */
+ if (! htab->symbian_p)
{
- flagword flags;
-
- flags = (SEC_HAS_CONTENTS | SEC_READONLY
- | SEC_IN_MEMORY | SEC_LINKER_CREATED);
- if ((sec->flags & SEC_ALLOC) != 0
- /* BPABI objects never have dynamic
- relocations mapped. */
- && !htab->symbian_p)
- flags |= SEC_ALLOC | SEC_LOAD;
- sreloc = bfd_make_section_with_flags (dynobj,
- name,
- flags);
- if (sreloc == NULL
- || ! bfd_set_section_alignment (dynobj, sreloc, 2))
- return FALSE;
- }
+ flagword flags;
- elf_section_data (sec)->sreloc = sreloc;
+ flags = bfd_get_section_flags (dynobj, sreloc);
+ flags &= ~(SEC_LOAD | SEC_ALLOC);
+ bfd_set_section_flags (dynobj, sreloc, flags);
+ }
}
/* If this is a global symbol, we count the number of
/* Find any dynamic relocs that apply to read-only sections. */
static bfd_boolean
-elf32_arm_readonly_dynrelocs (struct elf_link_hash_entry *h, PTR inf)
+elf32_arm_readonly_dynrelocs (struct elf_link_hash_entry * h, void * inf)
{
- struct elf32_arm_link_hash_entry *eh;
- struct elf32_arm_relocs_copied *p;
+ struct elf32_arm_link_hash_entry * eh;
+ struct elf32_arm_relocs_copied * p;
if (h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
/* If any dynamic relocs apply to a read-only section,
then we need a DT_TEXTREL entry. */
if ((info->flags & DF_TEXTREL) == 0)
- elf_link_hash_traverse (&htab->root, elf32_arm_readonly_dynrelocs,
- (PTR) info);
+ elf_link_hash_traverse (& htab->root, elf32_arm_readonly_dynrelocs,
+ info);
if ((info->flags & DF_TEXTREL) != 0)
{
bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
break;
}
- /* Fall through */
+ /* Fall through. */
case DT_REL:
case DT_RELA:
splt->contents + 8);
bfd_put_32 (output_bfd, got_address, splt->contents + 12);
- /* Generate a relocation for _GLOBAL_OFFSET_TABLE_. */
+ /* Generate a relocation for _GLOBAL_OFFSET_TABLE_. */
rel.r_offset = plt_address + 12;
rel.r_info = ELF32_R_INFO (htab->root.hgot->indx, R_ARM_ABS32);
rel.r_addend = 0;
};
-/* Output a single PLT mapping symbol. */
+/* Output a single mapping symbol. */
static bfd_boolean
-elf32_arm_ouput_plt_map_sym (output_arch_syminfo *osi,
- enum map_symbol_type type,
- bfd_vma offset)
+elf32_arm_output_map_sym (output_arch_syminfo *osi,
+ enum map_symbol_type type,
+ bfd_vma offset)
{
static const char *names[3] = {"$a", "$t", "$d"};
struct elf32_arm_link_hash_table *htab;
addr = h->plt.offset;
if (htab->symbian_p)
{
- if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_ARM, addr))
+ if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr))
return FALSE;
- if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_DATA, addr + 4))
+ if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 4))
return FALSE;
}
else if (htab->vxworks_p)
{
- if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_ARM, addr))
+ if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr))
return FALSE;
- if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_DATA, addr + 8))
+ if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 8))
return FALSE;
- if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_ARM, addr + 12))
+ if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr + 12))
return FALSE;
- if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_DATA, addr + 20))
+ if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 20))
return FALSE;
}
else
if (thumb_refs > 0)
{
- if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_THUMB, addr - 4))
+ if (!elf32_arm_output_map_sym (osi, ARM_MAP_THUMB, addr - 4))
return FALSE;
}
#ifdef FOUR_WORD_PLT
- if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_ARM, addr))
+ if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr))
return FALSE;
- if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_DATA, addr + 12))
+ if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 12))
return FALSE;
#else
/* A three-word PLT with no Thumb thunk contains only Arm code,
entries with thumb thunks. */
if (thumb_refs > 0 || addr == 20)
{
- if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_ARM, addr))
+ if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr))
return FALSE;
}
#endif
return TRUE;
}
+/* Output a single local symbol for a generated stub. */
+
+static bfd_boolean
+elf32_arm_output_stub_sym (output_arch_syminfo *osi, const char *name,
+ bfd_vma offset, bfd_vma size)
+{
+ struct elf32_arm_link_hash_table *htab;
+ Elf_Internal_Sym sym;
+
+ htab = elf32_arm_hash_table (osi->info);
+ sym.st_value = osi->sec->output_section->vma
+ + osi->sec->output_offset
+ + offset;
+ sym.st_size = size;
+ sym.st_other = 0;
+ sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FUNC);
+ sym.st_shndx = osi->sec_shndx;
+ if (!osi->func (osi->finfo, name, &sym, osi->sec, NULL))
+ return FALSE;
+ return TRUE;
+}
+
+static bfd_boolean
+arm_map_one_stub (struct bfd_hash_entry * gen_entry,
+ void * in_arg)
+{
+ struct elf32_arm_stub_hash_entry *stub_entry;
+ struct bfd_link_info *info;
+ struct elf32_arm_link_hash_table *htab;
+ asection *stub_sec;
+ bfd_vma addr;
+ char *stub_name;
+ output_arch_syminfo *osi;
+
+ /* Massage our args to the form they really have. */
+ stub_entry = (struct elf32_arm_stub_hash_entry *) gen_entry;
+ osi = (output_arch_syminfo *) in_arg;
+
+ info = osi->info;
+
+ htab = elf32_arm_hash_table (info);
+ stub_sec = stub_entry->stub_sec;
+
+ /* Ensure this stub is attached to the current section being
+ processed. */
+ if (stub_sec != osi->sec)
+ return TRUE;
+
+ addr = (bfd_vma) stub_entry->stub_offset;
+ stub_name = stub_entry->output_name;
+
+ switch (stub_entry->stub_type)
+ {
+ case arm_stub_long_branch:
+ if (!elf32_arm_output_stub_sym (osi, stub_name, addr, 8))
+ return FALSE;
+ if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr))
+ return FALSE;
+ if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 4))
+ return FALSE;
+ break;
+ case arm_thumb_v4t_stub_long_branch:
+ if (!elf32_arm_output_stub_sym (osi, stub_name, addr, 12))
+ return FALSE;
+ if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr))
+ return FALSE;
+ if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 8))
+ return FALSE;
+ break;
+ case arm_thumb_thumb_stub_long_branch:
+ if (!elf32_arm_output_stub_sym (osi, stub_name, addr | 1, 16))
+ return FALSE;
+ if (!elf32_arm_output_map_sym (osi, ARM_MAP_THUMB, addr))
+ return FALSE;
+ if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 12))
+ return FALSE;
+ break;
+ case arm_thumb_arm_v4t_stub_long_branch:
+ if (!elf32_arm_output_stub_sym (osi, stub_name, addr | 1, 20))
+ return FALSE;
+ if (!elf32_arm_output_map_sym (osi, ARM_MAP_THUMB, addr))
+ return FALSE;
+ if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr + 8))
+ return FALSE;
+ if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 16))
+ return FALSE;
+ break;
+ case arm_thumb_arm_v4t_stub_short_branch:
+ if (!elf32_arm_output_stub_sym (osi, stub_name, addr | 1, 8))
+ return FALSE;
+ if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr + 4))
+ return FALSE;
+ break;
+ case arm_stub_pic_long_branch:
+ if (!elf32_arm_output_stub_sym (osi, stub_name, addr, 12))
+ return FALSE;
+ if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr))
+ return FALSE;
+ if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 8))
+ return FALSE;
+ break;
+ default:
+ BFD_FAIL ();
+ }
+
+ return TRUE;
+}
/* Output mapping symbols for linker generated sections. */
for (offset = 0; offset < htab->arm_glue_size; offset += size)
{
- elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_ARM, offset);
- elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_DATA, offset + size - 4);
+ elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, offset);
+ elf32_arm_output_map_sym (&osi, ARM_MAP_DATA, offset + size - 4);
}
}
for (offset = 0; offset < htab->thumb_glue_size; offset += size)
{
- elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_THUMB, offset);
- elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_ARM, offset + 4);
+ elf32_arm_output_map_sym (&osi, ARM_MAP_THUMB, offset);
+ elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, offset + 4);
}
}
osi.sec_shndx = _bfd_elf_section_from_bfd_section
(output_bfd, osi.sec->output_section);
- elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_ARM, 0);
+ elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, 0);
+ }
+
+ /* Long calls stubs. */
+ if (htab->stub_bfd && htab->stub_bfd->sections)
+ {
+ asection* stub_sec;
+
+ for (stub_sec = htab->stub_bfd->sections;
+ stub_sec != NULL;
+ stub_sec = stub_sec->next)
+ {
+ /* Ignore non-stub sections. */
+ if (!strstr (stub_sec->name, STUB_SUFFIX))
+ continue;
+
+ osi.sec = stub_sec;
+
+ osi.sec_shndx = _bfd_elf_section_from_bfd_section
+ (output_bfd, osi.sec->output_section);
+
+ bfd_hash_traverse (&htab->stub_hash_table, arm_map_one_stub, &osi);
+ }
}
/* Finally, output mapping symbols for the PLT. */
return TRUE;
osi.sec_shndx = _bfd_elf_section_from_bfd_section (output_bfd,
- htab->splt->output_section);
+ htab->splt->output_section);
osi.sec = htab->splt;
/* Output mapping symbols for the plt header. SymbianOS does not have a
plt header. */
/* VxWorks shared libraries have no PLT header. */
if (!info->shared)
{
- if (!elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_ARM, 0))
+ if (!elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, 0))
return FALSE;
- if (!elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_DATA, 12))
+ if (!elf32_arm_output_map_sym (&osi, ARM_MAP_DATA, 12))
return FALSE;
}
}
else if (!htab->symbian_p)
{
- if (!elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_ARM, 0))
+ if (!elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, 0))
return FALSE;
#ifndef FOUR_WORD_PLT
- if (!elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_DATA, 16))
+ if (!elf32_arm_output_map_sym (&osi, ARM_MAP_DATA, 16))
return FALSE;
#endif
}
static bfd_boolean
elf32_arm_write_section (bfd *output_bfd,
- struct bfd_link_info *link_info, asection *sec,
+ struct bfd_link_info *link_info,
+ asection *sec,
bfd_byte *contents)
{
int mapcount, errcount;
/* New EABI objects mark thumb function symbols by setting the low bit of
the address. Turn these into STT_ARM_TFUNC. */
- if (ELF_ST_TYPE (dst->st_info) == STT_FUNC
+ if ((ELF_ST_TYPE (dst->st_info) == STT_FUNC)
&& (dst->st_value & 1))
{
dst->st_info = ELF_ST_INFO (ELF_ST_BIND (dst->st_info), STT_ARM_TFUNC);
}
-#undef elf32_bed
+#undef elf32_bed
#define elf32_bed elf32_arm_symbian_bed
/* The dynamic sections are not allocated on SymbianOS; the postlinker