bfd_elf_generic_reloc, /* special_function */
"R_ARM_THM_CALL", /* name */
FALSE, /* partial_inplace */
- 0x07ff07ff, /* src_mask */
- 0x07ff07ff, /* dst_mask */
+ 0x07ff2fff, /* src_mask */
+ 0x07ff2fff, /* dst_mask */
TRUE), /* pcrel_offset */
HOWTO (R_ARM_THM_PC8, /* type */
HOWTO (R_ARM_XPC25, /* type */
2, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
- 25, /* bitsize */
+ 24, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed,/* complain_on_overflow */
HOWTO (R_ARM_THM_XPC22, /* type */
2, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
- 22, /* bitsize */
+ 24, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed,/* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_ARM_THM_XPC22", /* name */
FALSE, /* partial_inplace */
- 0x07ff07ff, /* src_mask */
- 0x07ff07ff, /* dst_mask */
+ 0x07ff2fff, /* src_mask */
+ 0x07ff2fff, /* dst_mask */
TRUE), /* pcrel_offset */
/* Dynamic TLS relocations. */
return FALSE;
case 124: /* Linux/ARM elf_prpsinfo. */
+ elf_tdata (abfd)->core_pid
+ = bfd_get_32 (abfd, note->descdata + 12);
elf_tdata (abfd)->core_program
= _bfd_elfcore_strndup (abfd, note->descdata + 28, 16);
elf_tdata (abfd)->core_command
return TRUE;
}
+static char *
+elf32_arm_nabi_write_core_note (bfd *abfd, char *buf, int *bufsiz,
+ int note_type, ...)
+{
+ switch (note_type)
+ {
+ default:
+ return NULL;
+
+ case NT_PRPSINFO:
+ {
+ char data[124];
+ va_list ap;
+
+ va_start (ap, note_type);
+ memset (data, 0, sizeof (data));
+ strncpy (data + 28, va_arg (ap, const char *), 16);
+ strncpy (data + 44, va_arg (ap, const char *), 80);
+ va_end (ap);
+
+ return elfcore_write_note (abfd, buf, bufsiz,
+ "CORE", note_type, data, sizeof (data));
+ }
+
+ case NT_PRSTATUS:
+ {
+ char data[148];
+ va_list ap;
+ long pid;
+ int cursig;
+ const void *greg;
+
+ va_start (ap, note_type);
+ memset (data, 0, sizeof (data));
+ pid = va_arg (ap, long);
+ bfd_put_32 (abfd, pid, data + 24);
+ cursig = va_arg (ap, int);
+ bfd_put_16 (abfd, cursig, data + 12);
+ greg = va_arg (ap, const void *);
+ memcpy (data + 72, greg, 72);
+ va_end (ap);
+
+ return elfcore_write_note (abfd, buf, bufsiz,
+ "CORE", note_type, data, sizeof (data));
+ }
+ }
+}
+
#define TARGET_LITTLE_SYM bfd_elf32_littlearm_vec
#define TARGET_LITTLE_NAME "elf32-littlearm"
#define TARGET_BIG_SYM bfd_elf32_bigarm_vec
#define elf_backend_grok_prstatus elf32_arm_nabi_grok_prstatus
#define elf_backend_grok_psinfo elf32_arm_nabi_grok_psinfo
+#define elf_backend_write_core_note elf32_arm_nabi_write_core_note
typedef unsigned long int insn32;
typedef unsigned short int insn16;
ARM_REL_INSN(0xea000000, -8) /* b original_branch_dest. */
};
-/* Section name for stubs is the associated section name plus this
- string. */
-#define STUB_SUFFIX ".stub"
+/* For each section group there can be a specially created linker section
+ to hold the stubs for that group. The name of the stub section is based
+ upon the name of another section within that group with the suffix below
+ applied.
+
+ PR 13049: STUB_SUFFIX used to be ".stub", but this allowed the user to
+ create what appeared to be a linker stub section when it actually
+ contained user code/data. For example, consider this fragment:
+
+ const char * stubborn_problems[] = { "np" };
+
+ If this is compiled with "-fPIC -fdata-sections" then gcc produces a
+ section called:
+
+ .data.rel.local.stubborn_problems
+
+ This then causes problems in arm32_arm_build_stubs() as it triggers:
+
+ // Ignore non-stub sections.
+ if (!strstr (stub_sec->name, STUB_SUFFIX))
+ continue;
+
+ And so the section would be ignored instead of being processed. Hence
+ the change in definition of STUB_SUFFIX to a name that cannot be a valid
+ C identifier. */
+#define STUB_SUFFIX ".__stub"
/* One entry per long/short branch stub defined above. */
#define DEF_STUBS \
/* Whether we should fix the Cortex-A8 Thumb-2 branch/TLB erratum. */
int fix_cortex_a8;
+ /* Whether we should fix the ARM1176 BLX immediate issue. */
+ int fix_arm1176;
+
/* Nonzero if the ARM/Thumb BLX instructions are available for use. */
int use_blx;
ret->vfp11_erratum_glue_size = 0;
ret->num_vfp11_fixes = 0;
ret->fix_cortex_a8 = 0;
+ ret->fix_arm1176 = 0;
ret->bfd_of_glue_owner = NULL;
ret->byteswap_code = 0;
ret->target1_is_rel = 0;
case arm_stub_long_branch_v4t_thumb_arm:
case arm_stub_short_branch_v4t_thumb_arm:
case arm_stub_long_branch_v4t_thumb_arm_pic:
+ case arm_stub_long_branch_v4t_thumb_tls_pic:
case arm_stub_long_branch_thumb_only_pic:
return TRUE;
case arm_stub_none:
stub_type = (info->shared | globals->pic_veneer)
/* PIC stubs. */
? ((globals->use_blx
- && (r_type ==R_ARM_THM_CALL))
+ && (r_type == R_ARM_THM_CALL))
/* V5T and above. Stub starts with ARM code, so
we must be able to switch mode before
reaching it, which is only possible for 'bl'
/* non-PIC stubs. */
: ((globals->use_blx
- && (r_type ==R_ARM_THM_CALL))
+ && (r_type == R_ARM_THM_CALL))
/* V5T and above. */
? arm_stub_long_branch_any_any
/* V4T. */
asection *stub_sec;
link_sec = htab->stub_group[section->id].link_sec;
+ BFD_ASSERT (link_sec != NULL);
stub_sec = htab->stub_group[section->id].stub_sec;
+
if (stub_sec == NULL)
{
stub_sec = htab->stub_group[link_sec->id].stub_sec;
bfd_vma target;
enum elf32_arm_stub_type stub_type = arm_stub_none;
struct a8_erratum_reloc key, *found;
+ bfd_boolean use_plt = FALSE;
key.from = base_vma + i;
found = (struct a8_erratum_reloc *)
{
char *error_message = NULL;
struct elf_link_hash_entry *entry;
- bfd_boolean use_plt = FALSE;
/* We don't care about the error returned from this
function, only if there is glue or not. */
offset =
(bfd_signed_vma) (found->destination - pc_for_insn);
+ /* If the stub will use a Thumb-mode branch to a
+ PLT target, redirect it to the preceding Thumb
+ entry point. */
+ if (stub_type != arm_stub_a8_veneer_blx && use_plt)
+ offset -= PLT_THUMB_STUB_SIZE;
+
target = pc_for_insn + offset;
/* The BLX stub is ARM-mode code. Adjust the offset to
static void
check_use_blx (struct elf32_arm_link_hash_table *globals)
{
- if (bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC,
- Tag_CPU_arch) > 2)
- globals->use_blx = 1;
+ int cpu_arch;
+
+ cpu_arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC,
+ Tag_CPU_arch);
+
+ if (globals->fix_arm1176)
+ {
+ if (cpu_arch == TAG_CPU_ARCH_V6T2 || cpu_arch > TAG_CPU_ARCH_V6K)
+ globals->use_blx = 1;
+ }
+ else
+ {
+ if (cpu_arch > TAG_CPU_ARCH_V4T)
+ globals->use_blx = 1;
+ }
}
bfd_boolean
int use_blx,
bfd_arm_vfp11_fix vfp11_fix,
int no_enum_warn, int no_wchar_warn,
- int pic_veneer, int fix_cortex_a8)
+ int pic_veneer, int fix_cortex_a8,
+ int fix_arm1176)
{
struct elf32_arm_link_hash_table *globals;
globals->vfp11_fix = vfp11_fix;
globals->pic_veneer = pic_veneer;
globals->fix_cortex_a8 = fix_cortex_a8;
+ globals->fix_arm1176 = fix_arm1176;
BFD_ASSERT (is_arm_elf (output_bfd));
elf_arm_tdata (output_bfd)->no_enum_size_warning = no_enum_warn;
{
(*_bfd_error_handler)
(_("%B(%s): warning: interworking not enabled.\n"
- " first occurrence: %B: thumb call to arm"),
+ " first occurrence: %B: Thumb call to ARM"),
sym_sec->owner, input_bfd, name);
return FALSE;
{
/* The target is out of reach, so redirect the
branch to the local stub for this function. */
-
stub_entry = elf32_arm_get_stub_entry (input_section,
sym_sec, h,
rel, globals,
stub_type);
- if (stub_entry != NULL)
- value = (stub_entry->stub_offset
- + stub_entry->stub_sec->output_offset
- + stub_entry->stub_sec->output_section->vma);
+ {
+ if (stub_entry != NULL)
+ value = (stub_entry->stub_offset
+ + stub_entry->stub_sec->output_offset
+ + stub_entry->stub_sec->output_section->vma);
+
+ if (plt_offset != (bfd_vma) -1)
+ *unresolved_reloc_p = FALSE;
+ }
}
else
{
case, mode switching is performed by the stub. */
if (branch_type == ST_BRANCH_TO_THUMB && !stub_entry)
value |= (1 << 28);
- else
+ else if (stub_entry || branch_type != ST_BRANCH_UNKNOWN)
{
value &= ~(bfd_vma)(1 << 28);
value |= (1 << 24);
rel, globals,
stub_type);
if (stub_entry != NULL)
- value = (stub_entry->stub_offset
- + stub_entry->stub_sec->output_offset
- + stub_entry->stub_sec->output_section->vma);
+ {
+ value = (stub_entry->stub_offset
+ + stub_entry->stub_sec->output_offset
+ + stub_entry->stub_sec->output_section->vma);
+
+ if (plt_offset != (bfd_vma) -1)
+ *unresolved_reloc_p = FALSE;
+ }
/* If this call becomes a call to Arm, force BLX. */
if (globals->use_blx && (r_type == R_ARM_THM_CALL))
|| ELF32_R_TYPE(rel->r_info) == R_ARM_THM_TLS_CALL)
{
bfd_signed_vma offset;
+ /* TLS stubs are arm mode. The original symbol is a
+ data object, so branch_type is bogus. */
+ branch_type = ST_BRANCH_TO_ARM;
enum elf32_arm_stub_type stub_type
= arm_type_of_stub (info, input_section, rel,
st_type, &branch_type,
input_section->output_offset
+ rel->r_offset + 4);
- /* Round up the offset to a word boundary */
- offset = (offset + 2) & ~2;
+ if (stub_type != arm_stub_none
+ && arm_stub_is_thumb (stub_type))
+ {
+ lower_insn = 0xd000;
+ }
+ else
+ {
+ lower_insn = 0xc000;
+ /* Round up the offset to a word boundary */
+ offset = (offset + 2) & ~2;
+ }
+
neg = offset < 0;
upper_insn = (0xf000
| ((offset >> 12) & 0x3ff)
| (neg << 10));
- lower_insn = (0xc000
- | (((!((offset >> 23) & 1)) ^ neg) << 13)
+ lower_insn |= (((!((offset >> 23) & 1)) ^ neg) << 13)
| (((!((offset >> 22) & 1)) ^ neg) << 11)
- | ((offset >> 1) & 0x7ff));
+ | ((offset >> 1) & 0x7ff);
bfd_put_16 (input_bfd, upper_insn, hit_data);
bfd_put_16 (input_bfd, lower_insn, hit_data + 2);
return bfd_reloc_ok;
}
case R_ARM_TLS_LE32:
- if (info->shared)
+ if (info->shared && !info->pie)
{
(*_bfd_error_handler)
(_("%B(%A+0x%lx): R_ARM_TLS_LE32 relocation not permitted in shared object"),
- relocation;
addend += msec->output_section->vma + msec->output_offset;
- /* Cases here must match those in the preceeding
+ /* Cases here must match those in the preceding
switch statement. */
switch (r_type)
{
not process them. */
if (unresolved_reloc
&& !((input_section->flags & SEC_DEBUGGING) != 0
- && h->def_dynamic))
+ && h->def_dynamic)
+ && _bfd_elf_section_offset (output_bfd, info, input_section,
+ rel->r_offset) != (bfd_vma) -1)
{
(*_bfd_error_handler)
(_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
case Tag_PCS_config:
if (out_attr[i].i == 0)
out_attr[i].i = in_attr[i].i;
- else if (in_attr[i].i != 0 && out_attr[i].i != 0)
+ else if (in_attr[i].i != 0 && out_attr[i].i != in_attr[i].i)
{
/* It's sometimes ok to mix different configs, so this is only
a warning. */
struct elf_dyn_relocs *p;
if (h != NULL)
- pp = &((struct elf32_arm_link_hash_entry *) h)->dyn_relocs;
+ pp = &(eh->dyn_relocs);
else
{
Elf_Internal_Sym *isym;
if (pp == NULL)
return FALSE;
}
- for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
+ for (; (p = *pp) != NULL; pp = &p->next)
if (p->sec == sec)
{
/* Everything must go for SEC. */
Elf_Internal_Shdr **elf_shdrp;
bfd_boolean again;
+ _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook);
+
/* Marking EH data may cause additional code sections to be marked,
requiring multiple passes. */
again = TRUE;
/* We skip _bfd_dwarf1_find_nearest_line since no known ARM toolchain uses it. */
- if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
+ if (_bfd_dwarf2_find_nearest_line (abfd, dwarf_debug_sections,
+ section, symbols, offset,
filename_ptr, functionname_ptr,
line_ptr, 0,
& elf_tdata (abfd)->dwarf2_find_line_info))
if (h->root.type == bfd_link_hash_indirect)
return TRUE;
- if (h->root.type == bfd_link_hash_warning)
- /* When warning symbols are created, they **replace** the "real"
- entry in the hash table, thus we never get to see the real
- symbol in a hash traversal. So look at it now. */
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
eh = (struct elf32_arm_link_hash_entry *) h;
info = (struct bfd_link_info *) inf;
struct elf32_arm_link_hash_entry * eh;
struct elf_dyn_relocs * p;
- if (h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
eh = (struct elf32_arm_link_hash_entry *) h;
for (p = eh->dyn_relocs; p != NULL; p = p->next)
{
dynobj = elf_hash_table (info)->dynobj;
sgot = htab->root.sgotplt;
+ /* A broken linker script might have discarded the dynamic sections.
+ Catch this here so that we do not seg-fault later on. */
+ if (sgot != NULL && bfd_is_abs_section (sgot->output_section))
+ return FALSE;
sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
if (elf_hash_table (info)->dynamic_sections_created)
}
}
-/* Set the right machine number for an Arm ELF file. */
-
-static bfd_boolean
-elf32_arm_section_flags (flagword *flags, const Elf_Internal_Shdr *hdr)
-{
- if (hdr->sh_type == SHT_NOTE)
- *flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_SAME_CONTENTS;
-
- return TRUE;
-}
-
static void
elf32_arm_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED)
{
== SEC_HAS_CONTENTS
&& get_arm_elf_section_data (osi.sec) != NULL
&& get_arm_elf_section_data (osi.sec)->mapcount == 0
- && osi.sec->size > 0)
+ && osi.sec->size > 0
+ && (osi.sec->flags & SEC_EXCLUDE) == 0)
{
osi.sec_shndx = _bfd_elf_section_from_bfd_section
(output_bfd, osi.sec->output_section);
/* New EABI objects mark thumb function symbols by setting the low bit of
the address. */
- if ((ELF_ST_TYPE (dst->st_info) == STT_FUNC
- || ELF_ST_TYPE (dst->st_info) == STT_GNU_IFUNC)
- && (dst->st_value & 1))
+ if (ELF_ST_TYPE (dst->st_info) == STT_FUNC
+ || ELF_ST_TYPE (dst->st_info) == STT_GNU_IFUNC)
{
- dst->st_value &= ~(bfd_vma) 1;
- dst->st_target_internal = ST_BRANCH_TO_THUMB;
+ if (dst->st_value & 1)
+ {
+ dst->st_value &= ~(bfd_vma) 1;
+ dst->st_target_internal = ST_BRANCH_TO_THUMB;
+ }
+ else
+ dst->st_target_internal = ST_BRANCH_TO_ARM;
}
else if (ELF_ST_TYPE (dst->st_info) == STT_ARM_TFUNC)
{
else if (ELF_ST_TYPE (dst->st_info) == STT_SECTION)
dst->st_target_internal = ST_BRANCH_LONG;
else
- dst->st_target_internal = ST_BRANCH_TO_ARM;
+ dst->st_target_internal = ST_BRANCH_UNKNOWN;
return TRUE;
}
flagword *flagsp, asection **secp, bfd_vma *valp)
{
if ((abfd->flags & DYNAMIC) == 0
- && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
- elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+ && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
+ || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE))
+ elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
if (elf32_arm_hash_table (info)->vxworks_p
&& !elf_vxworks_add_symbol_hook (abfd, info, sym, namep,
#define elf_backend_post_process_headers elf32_arm_post_process_headers
#define elf_backend_reloc_type_class elf32_arm_reloc_type_class
#define elf_backend_object_p elf32_arm_object_p
-#define elf_backend_section_flags elf32_arm_section_flags
#define elf_backend_fake_sections elf32_arm_fake_sections
#define elf_backend_section_from_shdr elf32_arm_section_from_shdr
#define elf_backend_final_write_processing elf32_arm_final_write_processing
bfd_boolean flags_compatible = TRUE;
asection *sec;
- /* Check if we have the same endianess. */
+ /* Check if we have the same endianness. */
if (! _bfd_generic_verify_endian_match (ibfd, obfd))
return FALSE;