/* 32-bit ELF support for ARM
- Copyright (C) 1998-2018 Free Software Foundation, Inc.
+ Copyright (C) 1998-2019 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
#include <limits.h>
#include "bfd.h"
-#include "bfd_stdint.h"
#include "libiberty.h"
#include "libbfd.h"
#include "elf-bfd.h"
case NT_PRPSINFO:
{
- char data[124];
+ char data[124] ATTRIBUTE_NONSTRING;
va_list ap;
va_start (ap, note_type);
memset (data, 0, sizeof (data));
strncpy (data + 28, va_arg (ap, const char *), 16);
+#if GCC_VERSION == 8000 || GCC_VERSION == 8001
+ DIAGNOSTIC_PUSH;
+ /* GCC 8.0 and 8.1 warn about 80 equals destination size with
+ -Wstringop-truncation:
+ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85643
+ */
+ DIAGNOSTIC_IGNORE_STRINGOP_TRUNCATION;
+#endif
strncpy (data + 44, va_arg (ap, const char *), 80);
+#if GCC_VERSION == 8000 || GCC_VERSION == 8001
+ DIAGNOSTIC_POP;
+#endif
va_end (ap);
return elfcore_write_note (abfd, buf, bufsiz,
0xe599f000, /* ldr pc, [r9] */
};
+/* Thumb FDPIC PLT entry. */
+/* The last 5 words contain PLT lazy fragment code and data. */
+static const bfd_vma elf32_arm_fdpic_thumb_plt_entry [] =
+ {
+ 0xc00cf8df, /* ldr.w r12, .L1 */
+ 0x0c09eb0c, /* add.w r12, r12, r9 */
+ 0x9004f8dc, /* ldr.w r9, [r12, #4] */
+ 0xf000f8dc, /* ldr.w pc, [r12] */
+ 0x00000000, /* .L1 .word foo(GOTOFFFUNCDESC) */
+ 0x00000000, /* .L2 .word foo(funcdesc_value_reloc_offset) */
+ 0xc008f85f, /* ldr.w r12, .L2 */
+ 0xcd04f84d, /* push {r12} */
+ 0xc004f8d9, /* ldr.w r12, [r9, #4] */
+ 0xf000f8d9, /* ldr.w pc, [r9] */
+ };
+
#ifdef FOUR_WORD_PLT
/* The first entry in a procedure linkage table looks like
return TRUE;
}
+static bfd_boolean using_thumb_only (struct elf32_arm_link_hash_table *globals);
+
/* Return true if the PLT described by ARM_PLT requires a Thumb stub
before it. */
struct elf32_arm_link_hash_table *htab;
htab = elf32_arm_hash_table (info);
- return (arm_plt->thumb_refcount != 0
- || (!htab->use_blx && arm_plt->maybe_thumb_refcount != 0));
+
+ return (!using_thumb_only(htab) && (arm_plt->thumb_refcount != 0
+ || (!htab->use_blx && arm_plt->maybe_thumb_refcount != 0)));
}
/* Return a pointer to the head of the dynamic reloc list that should
arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, Tag_CPU_arch);
/* Force return logic to be reviewed for each new architecture. */
- BFD_ASSERT (arch <= TAG_CPU_ARCH_V8M_MAIN);
+ BFD_ASSERT (arch <= TAG_CPU_ARCH_V8_1M_MAIN);
if (arch == TAG_CPU_ARCH_V6_M
|| arch == TAG_CPU_ARCH_V6S_M
|| arch == TAG_CPU_ARCH_V7E_M
|| arch == TAG_CPU_ARCH_V8M_BASE
- || arch == TAG_CPU_ARCH_V8M_MAIN)
+ || arch == TAG_CPU_ARCH_V8M_MAIN
+ || arch == TAG_CPU_ARCH_V8_1M_MAIN)
return TRUE;
return FALSE;
arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, Tag_CPU_arch);
/* Force return logic to be reviewed for each new architecture. */
- BFD_ASSERT (arch <= TAG_CPU_ARCH_V8M_MAIN);
+ BFD_ASSERT (arch <= TAG_CPU_ARCH_V8_1M_MAIN);
return (arch == TAG_CPU_ARCH_V6T2
|| arch == TAG_CPU_ARCH_V7
|| arch == TAG_CPU_ARCH_V7E_M
|| arch == TAG_CPU_ARCH_V8
|| arch == TAG_CPU_ARCH_V8R
- || arch == TAG_CPU_ARCH_V8M_MAIN);
+ || arch == TAG_CPU_ARCH_V8M_MAIN
+ || arch == TAG_CPU_ARCH_V8_1M_MAIN);
}
/* Determine whether Thumb-2 BL instruction is available. */
bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, Tag_CPU_arch);
/* Force return logic to be reviewed for each new architecture. */
- BFD_ASSERT (arch <= TAG_CPU_ARCH_V8M_MAIN);
+ BFD_ASSERT (arch <= TAG_CPU_ARCH_V8_1M_MAIN);
/* Architecture was introduced after ARMv6T2 (eg. ARMv6-M). */
return (arch == TAG_CPU_ARCH_V6T2
Tag_CPU_arch);
/* Force return logic to be reviewed for each new architecture. */
- BFD_ASSERT (arch <= TAG_CPU_ARCH_V8M_MAIN);
+ BFD_ASSERT (arch <= TAG_CPU_ARCH_V8_1M_MAIN);
return (arch == TAG_CPU_ARCH_V6T2
|| arch == TAG_CPU_ARCH_V6K
asection *section;
Elf_Internal_Sym *local_syms = NULL;
- if (!is_arm_elf (input_bfd))
+ if (!is_arm_elf (input_bfd)
+ || (elf_dyn_lib_class (input_bfd) & DYN_AS_NEEDED) != 0)
continue;
num_a8_relocs = 0;
return;
globals->target1_is_rel = params->target1_is_rel;
- if (strcmp (params->target2_type, "rel") == 0)
+ if (globals->fdpic_p)
+ globals->target2_reloc = R_ARM_GOT32;
+ else if (strcmp (params->target2_type, "rel") == 0)
globals->target2_reloc = R_ARM_REL32;
else if (strcmp (params->target2_type, "abs") == 0)
globals->target2_reloc = R_ARM_ABS32;
arm_plt->got_offset = sgotplt->size - 8 * htab->num_tls_desc;
if (htab->fdpic_p)
/* Function descriptor takes 64 bits in GOT. */
- sgotplt->size += 8;
+ sgotplt->size += 8;
else
sgotplt->size += 4;
}
After the reserved .got.plt entries, all symbols appear in
the same order as in .plt. */
if (htab->fdpic_p)
- /* Function descriptor takes 8 bytes. */
- plt_index = (got_offset - got_header_size) / 8;
+ /* Function descriptor takes 8 bytes. */
+ plt_index = (got_offset - got_header_size) / 8;
else
- plt_index = (got_offset - got_header_size) / 4;
+ plt_index = (got_offset - got_header_size) / 4;
/* Calculate the address of the GOT entry. */
got_address = (sgot->output_section->vma
}
else if (htab->fdpic_p)
{
+ const bfd_vma *plt_entry = using_thumb_only(htab)
+ ? elf32_arm_fdpic_thumb_plt_entry
+ : elf32_arm_fdpic_plt_entry;
+
/* Fill-up Thumb stub if needed. */
if (elf32_arm_plt_needs_thumb_stub_p (info, arm_plt))
{
put_thumb_insn (htab, output_bfd,
elf32_arm_plt_thumb_stub[1], ptr - 2);
}
- put_arm_insn(htab, output_bfd,
- elf32_arm_fdpic_plt_entry[0], ptr + 0);
- put_arm_insn(htab, output_bfd,
- elf32_arm_fdpic_plt_entry[1], ptr + 4);
- put_arm_insn(htab, output_bfd,
- elf32_arm_fdpic_plt_entry[2], ptr + 8);
- put_arm_insn(htab, output_bfd,
- elf32_arm_fdpic_plt_entry[3], ptr + 12);
+ /* As we are using 32 bit instructions even for the Thumb
+ version, we have to use 'put_arm_insn' instead of
+ 'put_thumb_insn'. */
+ put_arm_insn(htab, output_bfd, plt_entry[0], ptr + 0);
+ put_arm_insn(htab, output_bfd, plt_entry[1], ptr + 4);
+ put_arm_insn(htab, output_bfd, plt_entry[2], ptr + 8);
+ put_arm_insn(htab, output_bfd, plt_entry[3], ptr + 12);
bfd_put_32 (output_bfd, got_offset, ptr + 16);
if (!(info->flags & DF_BIND_NOW))
bfd_put_32 (output_bfd,
htab->root.srelplt->reloc_count * RELOC_SIZE (htab),
ptr + 20);
- put_arm_insn(htab, output_bfd,
- elf32_arm_fdpic_plt_entry[6], ptr + 24);
- put_arm_insn(htab, output_bfd,
- elf32_arm_fdpic_plt_entry[7], ptr + 28);
- put_arm_insn(htab, output_bfd,
- elf32_arm_fdpic_plt_entry[8], ptr + 32);
- put_arm_insn(htab, output_bfd,
- elf32_arm_fdpic_plt_entry[9], ptr + 36);
+ put_arm_insn(htab, output_bfd, plt_entry[6], ptr + 24);
+ put_arm_insn(htab, output_bfd, plt_entry[7], ptr + 28);
+ put_arm_insn(htab, output_bfd, plt_entry[8], ptr + 32);
+ put_arm_insn(htab, output_bfd, plt_entry[9], ptr + 36);
}
}
else if (using_thumb_only (htab))
/* PR 21523: Use an absolute value. The user of this reloc will
have already selected an ADD or SUB insn appropriately. */
- value = labs (relocation);
+ value = llabs (relocation);
if (value >= 0x1000)
return bfd_reloc_overflow;
&& (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak))
outrel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE);
- else if (globals->fdpic_p)
- isrofixup = 1;
else
- outrel.r_info = 0;
+ {
+ outrel.r_info = 0;
+ if (globals->fdpic_p)
+ isrofixup = 1;
+ }
outrel.r_addend = dynreloc_value;
}
/* The GOT entry is initialized to zero by default.
See if we should install a different value. */
if (outrel.r_addend != 0
- && (outrel.r_info == 0 || globals->use_rel || isrofixup))
+ && (globals->use_rel || outrel.r_info == 0))
{
bfd_put_32 (output_bfd, outrel.r_addend,
sgot->contents + off);
outrel.r_addend = 0;
}
- if (outrel.r_info != 0 && !isrofixup)
+ if (isrofixup)
+ arm_elf_add_rofixup (output_bfd,
+ elf32_arm_hash_table(info)->srofixup,
+ sgot->output_section->vma
+ + sgot->output_offset + off);
+
+ else if (outrel.r_info != 0)
{
outrel.r_offset = (sgot->output_section->vma
+ sgot->output_offset
+ off);
elf32_arm_add_dynreloc (output_bfd, info, srelgot, &outrel);
}
- else if (isrofixup)
- {
- arm_elf_add_rofixup(output_bfd,
- elf32_arm_hash_table(info)->srofixup,
- sgot->output_section->vma
- + sgot->output_offset + off);
- }
+
h->got.offset |= 1;
}
value = sgot->output_offset + off;
off &= ~1;
else
{
- if (globals->use_rel)
- bfd_put_32 (output_bfd, dynreloc_value, sgot->contents + off);
+ Elf_Internal_Rela outrel;
+ int isrofixup = 0;
- if (bfd_link_pic (info) || dynreloc_st_type == STT_GNU_IFUNC)
+ if (dynreloc_st_type == STT_GNU_IFUNC)
+ outrel.r_info = ELF32_R_INFO (0, R_ARM_IRELATIVE);
+ else if (bfd_link_pic (info))
+ outrel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE);
+ else
{
- Elf_Internal_Rela outrel;
+ outrel.r_info = 0;
+ if (globals->fdpic_p)
+ isrofixup = 1;
+ }
+
+ /* The GOT entry is initialized to zero by default.
+ See if we should install a different value. */
+ if (globals->use_rel || outrel.r_info == 0)
+ bfd_put_32 (output_bfd, dynreloc_value, sgot->contents + off);
+ if (isrofixup)
+ arm_elf_add_rofixup (output_bfd,
+ globals->srofixup,
+ sgot->output_section->vma
+ + sgot->output_offset + off);
+
+ else if (outrel.r_info != 0)
+ {
outrel.r_addend = addend + dynreloc_value;
outrel.r_offset = (sgot->output_section->vma
+ sgot->output_offset
+ off);
- if (dynreloc_st_type == STT_GNU_IFUNC)
- outrel.r_info = ELF32_R_INFO (0, R_ARM_IRELATIVE);
- else
- outrel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE);
elf32_arm_add_dynreloc (output_bfd, info, srelgot, &outrel);
}
- else if (globals->fdpic_p)
- {
- /* For FDPIC executables, we use rofixup to fix
- address at runtime. */
- arm_elf_add_rofixup(output_bfd, globals->srofixup,
- sgot->output_section->vma + sgot->output_offset
- + off);
- }
local_got_offsets[r_symndx] |= 1;
}
case R_ARM_GOTOFFFUNCDESC:
{
- if (h == NULL)
+ if (h == NULL)
{
struct fdpic_local *local_fdpic_cnts = elf32_arm_local_fdpic_cnts(input_bfd);
int dynindx = elf_section_data (sym_sec->output_section)->dynindx;
case R_ARM_GOTFUNCDESC:
{
- if (h != NULL)
+ if (h != NULL)
{
Elf_Internal_Rela outrel;
outrel.r_addend = 0;
if (h->dynindx == -1 && !bfd_link_pic(info))
if (h->root.type == bfd_link_hash_undefweak)
- arm_elf_add_rofixup(output_bfd, globals->srofixup, -1);
+ arm_elf_add_rofixup(output_bfd, globals->srofixup, -1);
else
- arm_elf_add_rofixup(output_bfd, globals->srofixup, outrel.r_offset);
+ arm_elf_add_rofixup(output_bfd, globals->srofixup,
+ outrel.r_offset);
else
elf32_arm_add_dynreloc (output_bfd, info, srelgot, &outrel);
eh->fdpic_cnts.gotfuncdesc_offset |= 1;
case R_ARM_FUNCDESC:
{
- if (h == NULL)
+ if (h == NULL)
{
struct fdpic_local *local_fdpic_cnts = elf32_arm_local_fdpic_cnts(input_bfd);
Elf_Internal_Rela outrel;
switch (arch)
{
+ case TAG_CPU_ARCH_PRE_V4: return bfd_mach_arm_3M;
case TAG_CPU_ARCH_V4: return bfd_mach_arm_4;
case TAG_CPU_ARCH_V4T: return bfd_mach_arm_4T;
case TAG_CPU_ARCH_V5T: return bfd_mach_arm_5T;
return bfd_mach_arm_5TE;
}
+ case TAG_CPU_ARCH_V5TEJ:
+ return bfd_mach_arm_5TEJ;
+ case TAG_CPU_ARCH_V6:
+ return bfd_mach_arm_6;
+ case TAG_CPU_ARCH_V6KZ:
+ return bfd_mach_arm_6KZ;
+ case TAG_CPU_ARCH_V6T2:
+ return bfd_mach_arm_6T2;
+ case TAG_CPU_ARCH_V6K:
+ return bfd_mach_arm_6K;
+ case TAG_CPU_ARCH_V7:
+ return bfd_mach_arm_7;
+ case TAG_CPU_ARCH_V6_M:
+ return bfd_mach_arm_6M;
+ case TAG_CPU_ARCH_V6S_M:
+ return bfd_mach_arm_6SM;
+ case TAG_CPU_ARCH_V7E_M:
+ return bfd_mach_arm_7EM;
+ case TAG_CPU_ARCH_V8:
+ return bfd_mach_arm_8;
+ case TAG_CPU_ARCH_V8R:
+ return bfd_mach_arm_8R;
+ case TAG_CPU_ARCH_V8M_BASE:
+ return bfd_mach_arm_8M_BASE;
+ case TAG_CPU_ARCH_V8M_MAIN:
+ return bfd_mach_arm_8M_MAIN;
+ case TAG_CPU_ARCH_V8_1M_MAIN:
+ return bfd_mach_arm_8_1M_MAIN;
+
default:
+ /* Force entry to be added for any new known Tag_CPU_arch value. */
+ BFD_ASSERT (arch > MAX_TAG_CPU_ARCH);
+
+ /* Unknown Tag_CPU_arch value. */
return bfd_mach_arm_unknown;
}
}
T(V8M_MAIN), /* V8-M BASELINE. */
T(V8M_MAIN) /* V8-M MAINLINE. */
};
+ const int v8_1m_mainline[] =
+ {
+ -1, /* PRE_V4. */
+ -1, /* V4. */
+ -1, /* V4T. */
+ -1, /* V5T. */
+ -1, /* V5TE. */
+ -1, /* V5TEJ. */
+ -1, /* V6. */
+ -1, /* V6KZ. */
+ -1, /* V6T2. */
+ -1, /* V6K. */
+ T(V8_1M_MAIN), /* V7. */
+ T(V8_1M_MAIN), /* V6_M. */
+ T(V8_1M_MAIN), /* V6S_M. */
+ T(V8_1M_MAIN), /* V7E_M. */
+ -1, /* V8. */
+ -1, /* V8R. */
+ T(V8_1M_MAIN), /* V8-M BASELINE. */
+ T(V8_1M_MAIN), /* V8-M MAINLINE. */
+ -1, /* Unused (18). */
+ -1, /* Unused (19). */
+ -1, /* Unused (20). */
+ T(V8_1M_MAIN) /* V8.1-M MAINLINE. */
+ };
const int v4t_plus_v6_m[] =
{
-1, /* PRE_V4. */
-1, /* V8R. */
T(V8M_BASE), /* V8-M BASELINE. */
T(V8M_MAIN), /* V8-M MAINLINE. */
+ -1, /* Unused (18). */
+ -1, /* Unused (19). */
+ -1, /* Unused (20). */
+ T(V8_1M_MAIN), /* V8.1-M MAINLINE. */
T(V4T_PLUS_V6_M) /* V4T plus V6_M. */
};
const int *comb[] =
v8r,
v8m_baseline,
v8m_mainline,
+ NULL,
+ NULL,
+ NULL,
+ v8_1m_mainline,
/* Pseudo-architecture. */
v4t_plus_v6_m
};
/* This relocation describes which C++ vtable entries are actually
used. Record for later use during GC. */
case R_ARM_GNU_VTENTRY:
- BFD_ASSERT (h != NULL);
- if (h != NULL
- && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
+ if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
return FALSE;
break;
}
eh->fdpic_cnts.gotfuncdesc_offset = s->size;
s->size += 4;
if (h->dynindx == -1 && !bfd_link_pic(info))
- htab->srofixup->size += 4;
+ htab->srofixup->size += 4;
else
- elf32_arm_allocate_dynrelocs (info, htab->root.srelgot, 1);
+ elf32_arm_allocate_dynrelocs (info, htab->root.srelgot, 1);
}
if (eh->fdpic_cnts.funcdesc_cnt > 0)
}
/* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. On VxWorks,
- the _GLOBAL_OFFSET_TABLE_ symbol is not absolute: it is relative
- to the ".got" section. */
+ and for FDPIC, the _GLOBAL_OFFSET_TABLE_ symbol is not absolute:
+ it is relative to the ".got" section. */
if (h == htab->root.hdynamic
- || (!htab->vxworks_p && h == htab->root.hgot))
+ || (!htab->fdpic_p && !htab->vxworks_p && h == htab->root.hgot))
sym->st_shndx = SHN_ABS;
return TRUE;
}
else if (htab->fdpic_p)
{
+ enum map_symbol_type type = using_thumb_only(htab)
+ ? ARM_MAP_THUMB
+ : ARM_MAP_ARM;
+
if (elf32_arm_plt_needs_thumb_stub_p (osi->info, arm_plt))
- if (!elf32_arm_output_map_sym (osi, ARM_MAP_THUMB, addr - 4))
- return FALSE;
- if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr))
- return FALSE;
+ if (!elf32_arm_output_map_sym (osi, ARM_MAP_THUMB, addr - 4))
+ return FALSE;
+ if (!elf32_arm_output_map_sym (osi, type, addr))
+ return FALSE;
if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 16))
- return FALSE;
+ return FALSE;
if (htab->plt_entry_size == 4 * ARRAY_SIZE(elf32_arm_fdpic_plt_entry))
- if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr + 24))
- return FALSE;
+ if (!elf32_arm_output_map_sym (osi, type, addr + 24))
+ return FALSE;
}
else if (using_thumb_only (htab))
{
if (!elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, 0))
return FALSE;
}
- else if (using_thumb_only (htab))
+ else if (using_thumb_only (htab) && !htab->fdpic_p)
{
if (!elf32_arm_output_map_sym (&osi, ARM_MAP_THUMB, 0))
return FALSE;
Elf_Internal_Sym *sym, const char **namep,
flagword *flagsp, asection **secp, bfd_vma *valp)
{
- if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
- && (abfd->flags & DYNAMIC) == 0
- && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
- elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc;
-
if (elf32_arm_hash_table (info) == NULL)
return FALSE;
#define elf32_bed elf32_arm_fdpic_bed
#undef bfd_elf32_bfd_link_hash_table_create
-#define bfd_elf32_bfd_link_hash_table_create elf32_arm_fdpic_link_hash_table_create
+#define bfd_elf32_bfd_link_hash_table_create elf32_arm_fdpic_link_hash_table_create
#undef elf_backend_omit_section_dynsym
#define elf_backend_omit_section_dynsym elf32_arm_fdpic_omit_section_dynsym