/* AArch64-specific support for NN-bit ELF.
- Copyright (C) 2009-2015 Free Software Foundation, Inc.
+ Copyright (C) 2009-2019 Free Software Foundation, Inc.
Contributed by ARM Ltd.
This file is part of BFD, the Binary File Descriptor library.
fragments of the form:
adrp x0, :tlsgd:foo
- R_AARCH64_TLSGD_ADR_PAGE21(foo)
+ R_AARCH64_TLSGD_ADR_PAGE21(foo)
add x0, :tlsgd_lo12:foo
- R_AARCH64_TLSGD_ADD_LO12_NC(foo)
+ R_AARCH64_TLSGD_ADD_LO12_NC(foo)
bl __tls_get_addr
nop
For TLS descriptors the assembler will present us with code
fragments of the form:
- adrp x0, :tlsdesc:foo R_AARCH64_TLSDESC_ADR_PAGE21(foo)
- ldr x1, [x0, #:tlsdesc_lo12:foo] R_AARCH64_TLSDESC_LD64_LO12(foo)
- add x0, x0, #:tlsdesc_lo12:foo R_AARCH64_TLSDESC_ADD_LO12(foo)
+ adrp x0, :tlsdesc:foo R_AARCH64_TLSDESC_ADR_PAGE21(foo)
+ ldr x1, [x0, #:tlsdesc_lo12:foo] R_AARCH64_TLSDESC_LD64_LO12(foo)
+ add x0, x0, #:tlsdesc_lo12:foo R_AARCH64_TLSDESC_ADD_LO12(foo)
.tlsdesccall foo
- blr x1 R_AARCH64_TLSDESC_CALL(foo)
+ blr x1 R_AARCH64_TLSDESC_CALL(foo)
The relocations R_AARCH64_TLSGD_{ADR_PREL21,ADD_LO12_NC} against foo
indicate that foo is thread local and should be accessed via the
#include "bfd.h"
#include "libiberty.h"
#include "libbfd.h"
-#include "bfd_stdint.h"
#include "elf-bfd.h"
#include "bfdlink.h"
#include "objalloc.h"
#define HOWTO64(...) HOWTO (__VA_ARGS__)
#define HOWTO32(...) EMPTY_HOWTO (0)
#define LOG_FILE_ALIGN 3
+#define BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC BFD_RELOC_AARCH64_TLSDESC_LD64_LO12
#endif
#if ARCH_SIZE == 32
#define HOWTO64(...) EMPTY_HOWTO (0)
#define HOWTO32(...) HOWTO (__VA_ARGS__)
#define LOG_FILE_ALIGN 2
+#define BFD_RELOC_AARCH64_TLSDESC_LD32_LO12 BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC
+#define R_AARCH64_P32_TLSDESC_ADD_LO12 R_AARCH64_P32_TLSDESC_ADD_LO12_NC
#endif
#define IS_AARCH64_TLS_RELOC(R_TYPE) \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12 \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12 \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12_NC \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0 \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1 \
|| IS_AARCH64_TLSDESC_RELOC ((R_TYPE)))
#define IS_AARCH64_TLS_RELAX_RELOC(R_TYPE) \
- ((R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC \
+ ((R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADD \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADD_LO12 \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21 \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21 \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_CALL \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LD_PREL19 \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LDNN_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LDR \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_OFF_G1 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LDR \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21 \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_ADR_PREL21 \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_MOVW_G1 \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19 \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_LDNN_GOTTPREL_LO12_NC \
#define IS_AARCH64_TLSDESC_RELOC(R_TYPE) \
((R_TYPE) == BFD_RELOC_AARCH64_TLSDESC \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADD \
- || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADD_LO12 \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21 \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21 \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_CALL \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC \
- || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LD64_LO12 \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LDR \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LD_PREL19 \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_OFF_G1)
-#define ELIMINATE_COPY_RELOCS 0
+#define ELIMINATE_COPY_RELOCS 1
/* Return size of a relocation entry. HTAB is the bfd's
elf_aarch64_link_hash_entry. */
#define RELOC_SIZE(HTAB) (sizeof (ElfNN_External_Rela))
/* GOT Entry size - 8 bytes in ELF64 and 4 bytes in ELF32. */
-#define GOT_ENTRY_SIZE (ARCH_SIZE / 8)
-#define PLT_ENTRY_SIZE (32)
-#define PLT_SMALL_ENTRY_SIZE (16)
-#define PLT_TLSDESC_ENTRY_SIZE (32)
-
-/* Encoding of the nop instruction */
+#define GOT_ENTRY_SIZE (ARCH_SIZE / 8)
+#define PLT_ENTRY_SIZE (32)
+#define PLT_SMALL_ENTRY_SIZE (16)
+#define PLT_TLSDESC_ENTRY_SIZE (32)
+/* PLT sizes with BTI insn. */
+#define PLT_BTI_ENTRY_SIZE (36)
+#define PLT_BTI_SMALL_ENTRY_SIZE (20)
+#define PLT_BTI_TLSDESC_ENTRY_SIZE (36)
+/* PLT sizes with PAC insn. */
+#define PLT_PAC_ENTRY_SIZE (36)
+#define PLT_PAC_SMALL_ENTRY_SIZE (20)
+/* PLT sizes with BTI and PAC insn. */
+#define PLT_BTI_PAC_ENTRY_SIZE (40)
+#define PLT_BTI_PAC_SMALL_ENTRY_SIZE (24)
+
+/* Encoding of the nop instruction. */
#define INSN_NOP 0xd503201f
#define aarch64_compute_jump_table_size(htab) \
0x1f, 0x20, 0x03, 0xd5, /* nop */
};
+static const bfd_byte elfNN_aarch64_small_plt0_bti_entry[PLT_BTI_ENTRY_SIZE] =
+{
+ 0x5f, 0x24, 0x03, 0xd5, /* bti c. */
+ 0xf0, 0x7b, 0xbf, 0xa9, /* stp x16, x30, [sp, #-16]! */
+ 0x10, 0x00, 0x00, 0x90, /* adrp x16, (GOT+16) */
+#if ARCH_SIZE == 64
+ 0x11, 0x0A, 0x40, 0xf9, /* ldr x17, [x16, #PLT_GOT+0x10] */
+ 0x10, 0x42, 0x00, 0x91, /* add x16, x16,#PLT_GOT+0x10 */
+#else
+ 0x11, 0x0A, 0x40, 0xb9, /* ldr w17, [x16, #PLT_GOT+0x8] */
+ 0x10, 0x22, 0x00, 0x11, /* add w16, w16,#PLT_GOT+0x8 */
+#endif
+ 0x20, 0x02, 0x1f, 0xd6, /* br x17 */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+};
+
+static const bfd_byte elfNN_aarch64_small_plt0_pac_entry[PLT_PAC_ENTRY_SIZE] =
+{
+ 0xf0, 0x7b, 0xbf, 0xa9, /* stp x16, x30, [sp, #-16]! */
+ 0x10, 0x00, 0x00, 0x90, /* adrp x16, (GOT+16) */
+#if ARCH_SIZE == 64
+ 0x11, 0x0A, 0x40, 0xf9, /* ldr x17, [x16, #PLT_GOT+0x10] */
+ 0x10, 0x42, 0x00, 0x91, /* add x16, x16,#PLT_GOT+0x10 */
+#else
+ 0x11, 0x0A, 0x40, 0xb9, /* ldr w17, [x16, #PLT_GOT+0x8] */
+ 0x10, 0x22, 0x00, 0x11, /* add w16, w16,#PLT_GOT+0x8 */
+#endif
+ 0x9f, 0x21, 0x03, 0xd5, /* autia1716 */
+ 0x20, 0x02, 0x1f, 0xd6, /* br x17 */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+};
+
+static const bfd_byte
+elfNN_aarch64_small_plt0_bti_pac_entry[PLT_BTI_PAC_ENTRY_SIZE] =
+{
+ 0x5f, 0x24, 0x03, 0xd5, /* bti c. */
+ 0xf0, 0x7b, 0xbf, 0xa9, /* stp x16, x30, [sp, #-16]! */
+ 0x10, 0x00, 0x00, 0x90, /* adrp x16, (GOT+16) */
+#if ARCH_SIZE == 64
+ 0x11, 0x0A, 0x40, 0xf9, /* ldr x17, [x16, #PLT_GOT+0x10] */
+ 0x10, 0x42, 0x00, 0x91, /* add x16, x16,#PLT_GOT+0x10 */
+#else
+ 0x11, 0x0A, 0x40, 0xb9, /* ldr w17, [x16, #PLT_GOT+0x8] */
+ 0x10, 0x22, 0x00, 0x11, /* add w16, w16,#PLT_GOT+0x8 */
+#endif
+ 0x9f, 0x21, 0x03, 0xd5, /* autia1716 */
+ 0x20, 0x02, 0x1f, 0xd6, /* br x17 */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+};
+
/* Per function entry in a procedure linkage table looks like this
if the distance between the PLTGOT and the PLT is < 4GB use
- these PLT entries. */
+ these PLT entries. Use BTI versions of the PLTs when enabled. */
static const bfd_byte elfNN_aarch64_small_plt_entry[PLT_SMALL_ENTRY_SIZE] =
{
0x10, 0x00, 0x00, 0x90, /* adrp x16, PLTGOT + n * 8 */
0x20, 0x02, 0x1f, 0xd6, /* br x17. */
};
+static const bfd_byte
+elfNN_aarch64_small_plt_bti_entry[PLT_BTI_SMALL_ENTRY_SIZE] =
+{
+ 0x5f, 0x24, 0x03, 0xd5, /* bti c. */
+ 0x10, 0x00, 0x00, 0x90, /* adrp x16, PLTGOT + n * 8 */
+#if ARCH_SIZE == 64
+ 0x11, 0x02, 0x40, 0xf9, /* ldr x17, [x16, PLTGOT + n * 8] */
+ 0x10, 0x02, 0x00, 0x91, /* add x16, x16, :lo12:PLTGOT + n * 8 */
+#else
+ 0x11, 0x02, 0x40, 0xb9, /* ldr w17, [x16, PLTGOT + n * 4] */
+ 0x10, 0x02, 0x00, 0x11, /* add w16, w16, :lo12:PLTGOT + n * 4 */
+#endif
+ 0x20, 0x02, 0x1f, 0xd6, /* br x17. */
+};
+
+static const bfd_byte
+elfNN_aarch64_small_plt_pac_entry[PLT_PAC_SMALL_ENTRY_SIZE] =
+{
+ 0x10, 0x00, 0x00, 0x90, /* adrp x16, PLTGOT + n * 8 */
+#if ARCH_SIZE == 64
+ 0x11, 0x02, 0x40, 0xf9, /* ldr x17, [x16, PLTGOT + n * 8] */
+ 0x10, 0x02, 0x00, 0x91, /* add x16, x16, :lo12:PLTGOT + n * 8 */
+#else
+ 0x11, 0x02, 0x40, 0xb9, /* ldr w17, [x16, PLTGOT + n * 4] */
+ 0x10, 0x02, 0x00, 0x11, /* add w16, w16, :lo12:PLTGOT + n * 4 */
+#endif
+ 0x9f, 0x21, 0x03, 0xd5, /* autia1716 */
+ 0x20, 0x02, 0x1f, 0xd6, /* br x17. */
+};
+
+static const bfd_byte
+elfNN_aarch64_small_plt_bti_pac_entry[PLT_BTI_PAC_SMALL_ENTRY_SIZE] =
+{
+ 0x5f, 0x24, 0x03, 0xd5, /* bti c. */
+ 0x10, 0x00, 0x00, 0x90, /* adrp x16, PLTGOT + n * 8 */
+#if ARCH_SIZE == 64
+ 0x11, 0x02, 0x40, 0xf9, /* ldr x17, [x16, PLTGOT + n * 8] */
+ 0x10, 0x02, 0x00, 0x91, /* add x16, x16, :lo12:PLTGOT + n * 8 */
+#else
+ 0x11, 0x02, 0x40, 0xb9, /* ldr w17, [x16, PLTGOT + n * 4] */
+ 0x10, 0x02, 0x00, 0x11, /* add w16, w16, :lo12:PLTGOT + n * 4 */
+#endif
+ 0x9f, 0x21, 0x03, 0xd5, /* autia1716 */
+ 0x20, 0x02, 0x1f, 0xd6, /* br x17. */
+};
+
static const bfd_byte
elfNN_aarch64_tlsdesc_small_plt_entry[PLT_TLSDESC_ENTRY_SIZE] =
{
0x1f, 0x20, 0x03, 0xd5, /* nop */
};
-#define elf_info_to_howto elfNN_aarch64_info_to_howto
-#define elf_info_to_howto_rel elfNN_aarch64_info_to_howto
+static const bfd_byte
+elfNN_aarch64_tlsdesc_small_plt_bti_entry[PLT_BTI_TLSDESC_ENTRY_SIZE] =
+{
+ 0x5f, 0x24, 0x03, 0xd5, /* bti c. */
+ 0xe2, 0x0f, 0xbf, 0xa9, /* stp x2, x3, [sp, #-16]! */
+ 0x02, 0x00, 0x00, 0x90, /* adrp x2, 0 */
+ 0x03, 0x00, 0x00, 0x90, /* adrp x3, 0 */
+#if ARCH_SIZE == 64
+ 0x42, 0x00, 0x40, 0xf9, /* ldr x2, [x2, #0] */
+ 0x63, 0x00, 0x00, 0x91, /* add x3, x3, 0 */
+#else
+ 0x42, 0x00, 0x40, 0xb9, /* ldr w2, [x2, #0] */
+ 0x63, 0x00, 0x00, 0x11, /* add w3, w3, 0 */
+#endif
+ 0x40, 0x00, 0x1f, 0xd6, /* br x2 */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+ 0x1f, 0x20, 0x03, 0xd5, /* nop */
+};
+
+#define elf_info_to_howto elfNN_aarch64_info_to_howto
+#define elf_info_to_howto_rel elfNN_aarch64_info_to_howto
#define AARCH64_ELF_ABI_VERSION 0
/* Basic data relocations. */
-#if ARCH_SIZE == 64
- HOWTO (R_AARCH64_NULL, /* type */
+ /* Deprecated, but retained for backwards compatibility. */
+ HOWTO64 (R_AARCH64_NULL, /* type */
0, /* rightshift */
3, /* size (0 = byte, 1 = short, 2 = long) */
0, /* bitsize */
0, /* src_mask */
0, /* dst_mask */
FALSE), /* pcrel_offset */
-#else
HOWTO (R_AARCH64_NONE, /* type */
0, /* rightshift */
3, /* size (0 = byte, 1 = short, 2 = long) */
0, /* src_mask */
0, /* dst_mask */
FALSE), /* pcrel_offset */
-#endif
/* .xword: (S+A) */
HOWTO64 (AARCH64_R (ABS64), /* type */
HOWTO (AARCH64_R (MOVW_SABS_G0), /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
+ 17, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
HOWTO64 (AARCH64_R (MOVW_SABS_G1), /* type */
16, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
+ 17, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
HOWTO64 (AARCH64_R (MOVW_SABS_G2), /* type */
32, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
- 16, /* bitsize */
+ 17, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
+ /* Group relocations to create a 16, 32, 48 or 64 bit
+ PC relative address inline. */
+
+ /* MOV[NZ]: ((S+A-P) >> 0) & 0xffff */
+ HOWTO64 (AARCH64_R (MOVW_PREL_G0), /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 17, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_PREL_G0), /* name */
+ FALSE, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ /* MOVK: ((S+A-P) >> 0) & 0xffff [no overflow check] */
+ HOWTO64 (AARCH64_R (MOVW_PREL_G0_NC), /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_PREL_G0_NC), /* name */
+ FALSE, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ /* MOV[NZ]: ((S+A-P) >> 16) & 0xffff */
+ HOWTO64 (AARCH64_R (MOVW_PREL_G1), /* type */
+ 16, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 17, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_PREL_G1), /* name */
+ FALSE, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ /* MOVK: ((S+A-P) >> 16) & 0xffff [no overflow check] */
+ HOWTO64 (AARCH64_R (MOVW_PREL_G1_NC), /* type */
+ 16, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_PREL_G1_NC), /* name */
+ FALSE, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ /* MOV[NZ]: ((S+A-P) >> 32) & 0xffff */
+ HOWTO64 (AARCH64_R (MOVW_PREL_G2), /* type */
+ 32, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 17, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_PREL_G2), /* name */
+ FALSE, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ /* MOVK: ((S+A-P) >> 32) & 0xffff [no overflow check] */
+ HOWTO64 (AARCH64_R (MOVW_PREL_G2_NC), /* type */
+ 32, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_PREL_G2_NC), /* name */
+ FALSE, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ /* MOV[NZ]: ((S+A-P) >> 48) & 0xffff */
+ HOWTO64 (AARCH64_R (MOVW_PREL_G3), /* type */
+ 48, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_PREL_G3), /* name */
+ FALSE, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
/* Relocations to generate 19, 21 and 33 bit PC-relative load/store
addresses: PG(x) is (x & ~0xfff). */
0xfff, /* dst_mask */
FALSE), /* pcrel_offset */
- HOWTO (AARCH64_R (TLSDESC_LD_PREL19), /* type */
- 2, /* rightshift */
+ /* LD/ST16: bit[11:1] of byte offset to module TLS base address. */
+ HOWTO (AARCH64_R (TLSLE_LDST16_TPREL_LO12), /* type */
+ 1, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
- 19, /* bitsize */
- TRUE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
+ 11, /* bitsize */
+ FALSE, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
- AARCH64_R_STR (TLSDESC_LD_PREL19), /* name */
+ AARCH64_R_STR (TLSLE_LDST16_TPREL_LO12), /* name */
FALSE, /* partial_inplace */
- 0x0ffffe0, /* src_mask */
- 0x0ffffe0, /* dst_mask */
- TRUE), /* pcrel_offset */
+ 0x1ffc00, /* src_mask */
+ 0x1ffc00, /* dst_mask */
+ FALSE), /* pcrel_offset */
- HOWTO (AARCH64_R (TLSDESC_ADR_PREL21), /* type */
- 0, /* rightshift */
+ /* Same as BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12, but no overflow check. */
+ HOWTO (AARCH64_R (TLSLE_LDST16_TPREL_LO12_NC), /* type */
+ 1, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
- 21, /* bitsize */
- TRUE, /* pc_relative */
- 0, /* bitpos */
+ 11, /* bitsize */
+ FALSE, /* pc_relative */
+ 10, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
- AARCH64_R_STR (TLSDESC_ADR_PREL21), /* name */
+ AARCH64_R_STR (TLSLE_LDST16_TPREL_LO12_NC), /* name */
FALSE, /* partial_inplace */
- 0x1fffff, /* src_mask */
- 0x1fffff, /* dst_mask */
- TRUE), /* pcrel_offset */
+ 0x1ffc00, /* src_mask */
+ 0x1ffc00, /* dst_mask */
+ FALSE), /* pcrel_offset */
- /* Get to the page for the GOT entry for the symbol
- (G(S) - P) using an ADRP instruction. */
- HOWTO (AARCH64_R (TLSDESC_ADR_PAGE21), /* type */
- 12, /* rightshift */
+ /* LD/ST32: bit[11:2] of byte offset to module TLS base address. */
+ HOWTO (AARCH64_R (TLSLE_LDST32_TPREL_LO12), /* type */
+ 2, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
- 21, /* bitsize */
- TRUE, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
+ 10, /* bitsize */
+ FALSE, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
- AARCH64_R_STR (TLSDESC_ADR_PAGE21), /* name */
+ AARCH64_R_STR (TLSLE_LDST32_TPREL_LO12), /* name */
FALSE, /* partial_inplace */
- 0x1fffff, /* src_mask */
- 0x1fffff, /* dst_mask */
- TRUE), /* pcrel_offset */
+ 0xffc00, /* src_mask */
+ 0xffc00, /* dst_mask */
+ FALSE), /* pcrel_offset */
- /* LD64: GOT offset G(S) & 0xff8. */
- HOWTO64 (AARCH64_R (TLSDESC_LD64_LO12_NC), /* type */
- 3, /* rightshift */
+ /* Same as BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12, but no overflow check. */
+ HOWTO (AARCH64_R (TLSLE_LDST32_TPREL_LO12_NC), /* type */
+ 2, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
- 12, /* bitsize */
+ 10, /* bitsize */
FALSE, /* pc_relative */
- 0, /* bitpos */
+ 10, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
- AARCH64_R_STR (TLSDESC_LD64_LO12_NC), /* name */
+ AARCH64_R_STR (TLSLE_LDST32_TPREL_LO12_NC), /* name */
+ FALSE, /* partial_inplace */
+ 0xffc00, /* src_mask */
+ 0xffc00, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* LD/ST64: bit[11:3] of byte offset to module TLS base address. */
+ HOWTO (AARCH64_R (TLSLE_LDST64_TPREL_LO12), /* type */
+ 3, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 9, /* bitsize */
+ FALSE, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLE_LDST64_TPREL_LO12), /* name */
+ FALSE, /* partial_inplace */
+ 0x7fc00, /* src_mask */
+ 0x7fc00, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* Same as BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12, but no overflow check. */
+ HOWTO (AARCH64_R (TLSLE_LDST64_TPREL_LO12_NC), /* type */
+ 3, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 9, /* bitsize */
+ FALSE, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLE_LDST64_TPREL_LO12_NC), /* name */
+ FALSE, /* partial_inplace */
+ 0x7fc00, /* src_mask */
+ 0x7fc00, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* LD/ST8: bit[11:0] of byte offset to module TLS base address. */
+ HOWTO (AARCH64_R (TLSLE_LDST8_TPREL_LO12), /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 12, /* bitsize */
+ FALSE, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLE_LDST8_TPREL_LO12), /* name */
+ FALSE, /* partial_inplace */
+ 0x3ffc00, /* src_mask */
+ 0x3ffc00, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* Same as BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12, but no overflow check. */
+ HOWTO (AARCH64_R (TLSLE_LDST8_TPREL_LO12_NC), /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 12, /* bitsize */
+ FALSE, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLE_LDST8_TPREL_LO12_NC), /* name */
+ FALSE, /* partial_inplace */
+ 0x3ffc00, /* src_mask */
+ 0x3ffc00, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (AARCH64_R (TLSDESC_LD_PREL19), /* type */
+ 2, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 19, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSDESC_LD_PREL19), /* name */
+ FALSE, /* partial_inplace */
+ 0x0ffffe0, /* src_mask */
+ 0x0ffffe0, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ HOWTO (AARCH64_R (TLSDESC_ADR_PREL21), /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 21, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSDESC_ADR_PREL21), /* name */
+ FALSE, /* partial_inplace */
+ 0x1fffff, /* src_mask */
+ 0x1fffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ /* Get to the page for the GOT entry for the symbol
+ (G(S) - P) using an ADRP instruction. */
+ HOWTO (AARCH64_R (TLSDESC_ADR_PAGE21), /* type */
+ 12, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 21, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSDESC_ADR_PAGE21), /* name */
+ FALSE, /* partial_inplace */
+ 0x1fffff, /* src_mask */
+ 0x1fffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ /* LD64: GOT offset G(S) & 0xff8. */
+ HOWTO64 (AARCH64_R (TLSDESC_LD64_LO12), /* type */
+ 3, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 12, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSDESC_LD64_LO12), /* name */
FALSE, /* partial_inplace */
0xff8, /* src_mask */
0xff8, /* dst_mask */
FALSE), /* pcrel_offset */
/* ADD: GOT offset G(S) & 0xfff. */
- HOWTO (AARCH64_R (TLSDESC_ADD_LO12_NC), /* type */
+ HOWTO (AARCH64_R (TLSDESC_ADD_LO12), /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
12, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
+ complain_overflow_dont,/* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
- AARCH64_R_STR (TLSDESC_ADD_LO12_NC), /* name */
+ AARCH64_R_STR (TLSDESC_ADD_LO12), /* name */
FALSE, /* partial_inplace */
0xfff, /* src_mask */
0xfff, /* dst_mask */
12, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
+ complain_overflow_unsigned, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
AARCH64_R_STR (TLSDESC_OFF_G1), /* name */
FALSE, /* partial_inplace */
/* Given R_TYPE, return the bfd internal relocation enumerator. */
static bfd_reloc_code_real_type
-elfNN_aarch64_bfd_reloc_from_type (unsigned int r_type)
+elfNN_aarch64_bfd_reloc_from_type (bfd *abfd, unsigned int r_type)
{
static bfd_boolean initialized_p = FALSE;
/* Indexed by R_TYPE, values are offsets in the howto_table. */
static unsigned int offsets[R_AARCH64_end];
- if (initialized_p == FALSE)
+ if (!initialized_p)
{
unsigned int i;
/* PR 17512: file: b371e70a. */
if (r_type >= R_AARCH64_end)
{
- _bfd_error_handler (_("Invalid AArch64 reloc number: %d"), r_type);
+ _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
+ abfd, r_type);
bfd_set_error (bfd_error_bad_value);
return BFD_RELOC_AARCH64_NONE;
}
}
static reloc_howto_type *
-elfNN_aarch64_howto_from_type (unsigned int r_type)
+elfNN_aarch64_howto_from_type (bfd *abfd, unsigned int r_type)
{
bfd_reloc_code_real_type val;
reloc_howto_type *howto;
if (r_type == R_AARCH64_NONE)
return &elfNN_aarch64_howto_none;
- val = elfNN_aarch64_bfd_reloc_from_type (r_type);
+ val = elfNN_aarch64_bfd_reloc_from_type (abfd, r_type);
howto = elfNN_aarch64_howto_from_bfd_reloc (val);
if (howto != NULL)
return NULL;
}
-static void
-elfNN_aarch64_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *bfd_reloc,
+static bfd_boolean
+elfNN_aarch64_info_to_howto (bfd *abfd, arelent *bfd_reloc,
Elf_Internal_Rela *elf_reloc)
{
unsigned int r_type;
r_type = ELFNN_R_TYPE (elf_reloc->r_info);
- bfd_reloc->howto = elfNN_aarch64_howto_from_type (r_type);
+ bfd_reloc->howto = elfNN_aarch64_howto_from_type (abfd, r_type);
+
+ if (bfd_reloc->howto == NULL)
+ {
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: unsupported relocation type %#x"), abfd, r_type);
+ return FALSE;
+ }
+ return TRUE;
}
static reloc_howto_type *
return NULL;
}
-#define TARGET_LITTLE_SYM aarch64_elfNN_le_vec
-#define TARGET_LITTLE_NAME "elfNN-littleaarch64"
-#define TARGET_BIG_SYM aarch64_elfNN_be_vec
-#define TARGET_BIG_NAME "elfNN-bigaarch64"
+#define TARGET_LITTLE_SYM aarch64_elfNN_le_vec
+#define TARGET_LITTLE_NAME "elfNN-littleaarch64"
+#define TARGET_BIG_SYM aarch64_elfNN_be_vec
+#define TARGET_BIG_NAME "elfNN-bigaarch64"
/* The linker script knows the section names for placement.
The entry_names are used to do simple name mangling on the stubs.
/* Zero to warn when linking objects with incompatible wchar_t sizes. */
int no_wchar_size_warning;
+
+ /* All GNU_PROPERTY_AARCH64_FEATURE_1_AND properties. */
+ uint32_t gnu_and_prop;
+
+ /* Zero to warn when linking objects with incompatible
+ GNU_PROPERTY_AARCH64_FEATURE_1_BTI. */
+ int no_bti_warn;
+
+ /* PLT type based on security. */
+ aarch64_plt_type plt_type;
};
#define elf_aarch64_tdata(bfd) \
/* Enable ADRP->ADR rewrite for erratum 843419 workaround. */
int fix_erratum_843419_adr;
+ /* Don't apply link-time values for dynamic relocations. */
+ int no_apply_dynamic_relocs;
+
/* The number of bytes in the initial entry in the PLT. */
bfd_size_type plt_header_size;
- /* The number of bytes in the subsequent PLT etries. */
+ /* The bytes of the initial PLT entry. */
+ const bfd_byte *plt0_entry;
+
+ /* The number of bytes in the subsequent PLT entries. */
bfd_size_type plt_entry_size;
- /* Short-cuts to get to dynamic linker sections. */
- asection *sdynbss;
- asection *srelbss;
+ /* The bytes of the subsequent PLT entry. */
+ const bfd_byte *plt_entry;
/* Small local sym cache. */
struct sym_cache sym_cache;
yet. */
bfd_vma tlsdesc_plt;
+ /* The number of bytes in the PLT enty for the TLS descriptor. */
+ bfd_size_type tlsdesc_plt_entry_size;
+
/* The GOT offset for the lazy trampoline. Communicated to the
loader via DT_TLSDESC_GOT. The magic value (bfd_vma) -1
indicates an offset is not allocated. */
}
ret->plt_header_size = PLT_ENTRY_SIZE;
+ ret->plt0_entry = elfNN_aarch64_small_plt0_entry;
ret->plt_entry_size = PLT_SMALL_ENTRY_SIZE;
+ ret->plt_entry = elfNN_aarch64_small_plt_entry;
+ ret->tlsdesc_plt_entry_size = PLT_TLSDESC_ENTRY_SIZE;
ret->obfd = abfd;
ret->dt_tlsdesc_got = (bfd_vma) - 1;
return &ret->root.root;
}
+/* Perform relocation R_TYPE. Returns TRUE upon success, FALSE otherwise. */
+
static bfd_boolean
aarch64_relocate (unsigned int r_type, bfd *input_bfd, asection *input_section,
bfd_vma offset, bfd_vma value)
reloc_howto_type *howto;
bfd_vma place;
- howto = elfNN_aarch64_howto_from_type (r_type);
+ howto = elfNN_aarch64_howto_from_type (input_bfd, r_type);
place = (input_section->output_section->vma + input_section->output_offset
+ offset);
- r_type = elfNN_aarch64_bfd_reloc_from_type (r_type);
+ r_type = elfNN_aarch64_bfd_reloc_from_type (input_bfd, r_type);
value = _bfd_aarch64_elf_resolve_relocation (r_type, place, value, 0, FALSE);
return _bfd_aarch64_elf_put_addend (input_bfd,
input_section->contents + offset, r_type,
- howto, value);
+ howto, value) == bfd_reloc_ok;
}
static enum elf_aarch64_stub_type
/* Determine the type of stub needed, if any, for a call. */
static enum elf_aarch64_stub_type
-aarch64_type_of_stub (struct bfd_link_info *info,
- asection *input_sec,
+aarch64_type_of_stub (asection *input_sec,
const Elf_Internal_Rela *rel,
asection *sym_sec,
unsigned char st_type,
- struct elf_aarch64_link_hash_entry *hash,
bfd_vma destination)
{
bfd_vma location;
bfd_signed_vma branch_offset;
unsigned int r_type;
- struct elf_aarch64_link_hash_table *globals;
enum elf_aarch64_stub_type stub_type = aarch64_stub_none;
- bfd_boolean via_plt_p;
if (st_type != STT_FUNC
- && (sym_sec != bfd_abs_section_ptr))
+ && (sym_sec == input_sec))
return stub_type;
- globals = elf_aarch64_hash_table (info);
- via_plt_p = (globals->root.splt != NULL && hash != NULL
- && hash->root.plt.offset != (bfd_vma) - 1);
- /* Make sure call to plt stub can fit into the branch range. */
- if (via_plt_p)
- destination = (globals->root.splt->output_section->vma
- + globals->root.splt->output_offset
- + hash->root.plt.offset);
-
/* Determine where the call point is. */
location = (input_sec->output_offset
+ input_sec->output_section->vma + rel->r_offset);
return stub_name;
}
+/* Return TRUE if symbol H should be hashed in the `.gnu.hash' section. For
+ executable PLT slots where the executable never takes the address of those
+ functions, the function symbols are not added to the hash table. */
+
+static bfd_boolean
+elf_aarch64_hash_symbol (struct elf_link_hash_entry *h)
+{
+ if (h->plt.offset != (bfd_vma) -1
+ && !h->def_regular
+ && !h->pointer_equality_needed)
+ return FALSE;
+
+ return _bfd_elf_hash_symbol (h);
+}
+
+
/* Look up an entry in the stub hash. Stub entries are cached because
creating the stub name takes a bit of time. */
TRUE, FALSE);
if (stub_entry == NULL)
{
- (*_bfd_error_handler) (_("%s: cannot create stub entry %s"),
- section->owner, stub_name);
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: cannot create stub entry %s"),
+ section->owner, stub_name);
return NULL;
}
TRUE, FALSE);
if (stub_entry == NULL)
{
- (*_bfd_error_handler) (_("cannot create stub entry %s"), stub_name);
+ _bfd_error_handler (_("cannot create stub entry %s"), stub_name);
return NULL;
}
switch (stub_entry->stub_type)
{
case aarch64_stub_adrp_branch:
- if (aarch64_relocate (AARCH64_R (ADR_PREL_PG_HI21), stub_bfd, stub_sec,
- stub_entry->stub_offset, sym_value))
+ if (!aarch64_relocate (AARCH64_R (ADR_PREL_PG_HI21), stub_bfd, stub_sec,
+ stub_entry->stub_offset, sym_value))
/* The stub would not have been relaxed if the offset was out
of range. */
BFD_FAIL ();
- if (aarch64_relocate (AARCH64_R (ADD_ABS_LO12_NC), stub_bfd, stub_sec,
- stub_entry->stub_offset + 4, sym_value))
+ if (!aarch64_relocate (AARCH64_R (ADD_ABS_LO12_NC), stub_bfd, stub_sec,
+ stub_entry->stub_offset + 4, sym_value))
BFD_FAIL ();
break;
case aarch64_stub_long_branch:
/* We want the value relative to the address 12 bytes back from the
- value itself. */
- if (aarch64_relocate (AARCH64_R (PRELNN), stub_bfd, stub_sec,
- stub_entry->stub_offset + 16, sym_value + 12))
+ value itself. */
+ if (!aarch64_relocate (AARCH64_R (PRELNN), stub_bfd, stub_sec,
+ stub_entry->stub_offset + 16, sym_value + 12))
BFD_FAIL ();
break;
break;
case aarch64_stub_erratum_843419_veneer:
- if (aarch64_relocate (AARCH64_R (JUMP26), stub_bfd, stub_sec,
- stub_entry->stub_offset + 4, sym_value + 4))
+ if (!aarch64_relocate (AARCH64_R (JUMP26), stub_bfd, stub_sec,
+ stub_entry->stub_offset + 4, sym_value + 4))
BFD_FAIL ();
break;
For scalar LD/ST instructions PAIR is FALSE, RT is returned and RT2
is set equal to RT.
- For LD/ST pair instructions PAIR is TRUE, RT and RT2 are returned.
-
- */
+ For LD/ST pair instructions PAIR is TRUE, RT and RT2 are returned. */
static bfd_boolean
aarch64_mem_op_p (uint32_t insn, unsigned int *rt, unsigned int *rt2,
uint32_t v = 0;
uint32_t opc_v = 0;
- /* Bail out quickly if INSN doesn't fall into the the load-store
+ /* Bail out quickly if INSN doesn't fall into the load-store
encoding space. */
if (!AARCH64_LDST (insn))
return FALSE;
*rt = AARCH64_RT (insn);
*rt2 = *rt;
if (AARCH64_BIT (insn, 21) == 1)
- {
+ {
*pair = TRUE;
*rt2 = AARCH64_RT2 (insn);
}
{
char *stub_name = (char *) bfd_malloc
(strlen ("__erratum_835769_veneer_") + 16);
- sprintf (stub_name,"__erratum_835769_veneer_%d", num_fixes);
+ if (stub_name != NULL)
+ sprintf (stub_name,"__erratum_835769_veneer_%d", num_fixes);
return stub_name;
}
static bfd_boolean
_bfd_aarch64_adrp_p (uint32_t insn)
{
- return ((insn & 0x9f000000) == 0x90000000);
+ return ((insn & AARCH64_ADRP_OP_MASK) == AARCH64_ADRP_OP);
}
if (!strstr (section->name, STUB_SUFFIX))
continue;
+ /* Add space for a branch. Add 8 bytes to keep section 8 byte aligned,
+ as long branch stubs contain a 64-bit address. */
if (section->size)
- section->size += 4;
+ section->size += 8;
/* Ensure all stub sections have a size which is a multiple of
4096. This is important in order to ensure that the insertion
}
}
-
-/* Construct an erratum 843419 workaround stub name.
- */
+/* Construct an erratum 843419 workaround stub name. */
static char *
_bfd_aarch64_erratum_843419_stub_name (asection *input_section,
struct elf_aarch64_stub_hash_entry *stub_entry;
stub_name = _bfd_aarch64_erratum_843419_stub_name (section, ldst_offset);
+ if (stub_name == NULL)
+ return FALSE;
stub_entry = aarch64_stub_hash_lookup (&htab->stub_hash_table, stub_name,
FALSE, FALSE);
if (stub_entry)
If we placed workaround veneers in any other stub section then we
could not assume that all relocations have been processed on the
corresponding input section at the point we output the stub
- section.
- */
+ section. */
stub_entry = _bfd_aarch64_add_stub_entry_after (stub_name, section, htab);
if (stub_entry == NULL)
}
/* Determine what (if any) linker stub is needed. */
- stub_type = aarch64_type_of_stub
- (info, section, irela, sym_sec, st_type, hash, destination);
+ stub_type = aarch64_type_of_stub (section, irela, sym_sec,
+ st_type, destination);
if (stub_type == aarch64_stub_none)
continue;
{
/* The proper stub has already been created. */
free (stub_name);
+ /* Always update this stub's target since it may have
+ changed after layout. */
+ stub_entry->target_value = sym_value + irela->r_addend;
continue;
}
goto error_ret_free_internal;
}
- stub_entry->target_value = sym_value;
+ stub_entry->target_value = sym_value + irela->r_addend;
stub_entry->target_section = sym_sec;
stub_entry->stub_type = stub_type;
stub_entry->h = hash;
return FALSE;
stub_sec->size = 0;
+ /* Add a branch around the stub section, and a nop, to keep it 8 byte
+ aligned, as long branch stubs contain a 64-bit address. */
bfd_putl32 (0x14000000 | (size >> 2), stub_sec->contents);
- stub_sec->size += 4;
+ bfd_putl32 (INSN_NOP, stub_sec->contents + 4);
+ stub_sec->size += 8;
}
/* Build the stubs as directed by the stub hash table. */
}
}
+static void
+setup_plt_values (struct bfd_link_info *link_info,
+ aarch64_plt_type plt_type)
+{
+ struct elf_aarch64_link_hash_table *globals;
+ globals = elf_aarch64_hash_table (link_info);
+
+ if (plt_type == PLT_BTI_PAC)
+ {
+ globals->plt_header_size = PLT_BTI_PAC_ENTRY_SIZE;
+ globals->plt0_entry = elfNN_aarch64_small_plt0_bti_pac_entry;
+ globals->tlsdesc_plt_entry_size = PLT_BTI_TLSDESC_ENTRY_SIZE;
+
+ /* Only in ET_EXEC we need PLTn with BTI. */
+ if (bfd_link_pde (link_info))
+ {
+ globals->plt_entry_size = PLT_BTI_PAC_SMALL_ENTRY_SIZE;
+ globals->plt_entry = elfNN_aarch64_small_plt_bti_pac_entry;
+ }
+ else
+ {
+ globals->plt_entry_size = PLT_PAC_SMALL_ENTRY_SIZE;
+ globals->plt_entry = elfNN_aarch64_small_plt_pac_entry;
+ }
+ }
+ else if (plt_type == PLT_BTI)
+ {
+ globals->plt_header_size = PLT_BTI_ENTRY_SIZE;
+ globals->plt0_entry = elfNN_aarch64_small_plt0_bti_entry;
+ globals->tlsdesc_plt_entry_size = PLT_BTI_TLSDESC_ENTRY_SIZE;
+
+ /* Only in ET_EXEC we need PLTn with BTI. */
+ if (bfd_link_pde (link_info))
+ {
+ globals->plt_entry_size = PLT_BTI_SMALL_ENTRY_SIZE;
+ globals->plt_entry = elfNN_aarch64_small_plt_bti_entry;
+ }
+ }
+ else if (plt_type == PLT_PAC)
+ {
+ globals->plt_header_size = PLT_PAC_ENTRY_SIZE;
+ globals->plt0_entry = elfNN_aarch64_small_plt0_pac_entry;
+ globals->tlsdesc_plt_entry_size = PLT_TLSDESC_ENTRY_SIZE;
+ globals->plt_entry_size = PLT_PAC_SMALL_ENTRY_SIZE;
+ globals->plt_entry = elfNN_aarch64_small_plt_pac_entry;
+ }
+}
+
/* Set option values needed during linking. */
void
bfd_elfNN_aarch64_set_options (struct bfd *output_bfd,
int no_enum_warn,
int no_wchar_warn, int pic_veneer,
int fix_erratum_835769,
- int fix_erratum_843419)
+ int fix_erratum_843419,
+ int no_apply_dynamic_relocs,
+ aarch64_bti_pac_info bp_info)
{
struct elf_aarch64_link_hash_table *globals;
globals->fix_erratum_835769 = fix_erratum_835769;
globals->fix_erratum_843419 = fix_erratum_843419;
globals->fix_erratum_843419_adr = TRUE;
+ globals->no_apply_dynamic_relocs = no_apply_dynamic_relocs;
BFD_ASSERT (is_aarch64_elf (output_bfd));
elf_aarch64_tdata (output_bfd)->no_enum_size_warning = no_enum_warn;
elf_aarch64_tdata (output_bfd)->no_wchar_size_warning = no_wchar_warn;
+
+ switch (bp_info.bti_type)
+ {
+ case BTI_WARN:
+ elf_aarch64_tdata (output_bfd)->no_bti_warn = 0;
+ elf_aarch64_tdata (output_bfd)->gnu_and_prop
+ |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
+ break;
+
+ default:
+ break;
+ }
+ elf_aarch64_tdata (output_bfd)->plt_type = bp_info.plt_type;
+ setup_plt_values (link_info, bp_info.plt_type);
}
static bfd_vma
? BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1
: BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19);
+ case BFD_RELOC_AARCH64_TLSDESC_LDR:
+ return (is_local
+ ? BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC
+ : BFD_RELOC_AARCH64_NONE);
+
+ case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC:
+ return (is_local
+ ? BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC
+ : BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC);
+
+ case BFD_RELOC_AARCH64_TLSDESC_OFF_G1:
+ return (is_local
+ ? BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2
+ : BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1);
+
case BFD_RELOC_AARCH64_TLSDESC_LDNN_LO12_NC:
case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC:
return (is_local
? BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12
: BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19);
- case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSDESC_ADD:
+ case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12:
case BFD_RELOC_AARCH64_TLSDESC_CALL:
/* Instructions with these relocations will become NOPs. */
return BFD_RELOC_AARCH64_NONE;
case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21:
return is_local ? BFD_RELOC_AARCH64_NONE : r_type;
+#if ARCH_SIZE == 64
+ case BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC:
+ return is_local
+ ? BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC
+ : BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC;
+
+ case BFD_RELOC_AARCH64_TLSGD_MOVW_G1:
+ return is_local
+ ? BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2
+ : BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1;
+#endif
+
default:
break;
}
case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21:
return GOT_TLS_GD;
- case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSDESC_ADD:
+ case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12:
case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21:
case BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21:
case BFD_RELOC_AARCH64_TLSDESC_CALL:
case BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC:
- case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12:
case BFD_RELOC_AARCH64_TLSDESC_LD_PREL19:
+ case BFD_RELOC_AARCH64_TLSDESC_LDR:
+ case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC:
+ case BFD_RELOC_AARCH64_TLSDESC_OFF_G1:
return GOT_TLSDESC_GD;
case BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
if (symbol_got_type == GOT_TLS_IE && GOT_TLS_GD_ANY_P (reloc_got_type))
return TRUE;
- if (bfd_link_pic (info))
+ if (!bfd_link_executable (info))
return FALSE;
if (h && h->root.type == bfd_link_hash_undefweak)
unsigned long r_symndx)
{
bfd_reloc_code_real_type bfd_r_type
- = elfNN_aarch64_bfd_reloc_from_type (r_type);
+ = elfNN_aarch64_bfd_reloc_from_type (input_bfd, r_type);
if (! aarch64_can_relax_tls (input_bfd, info, bfd_r_type, h, r_symndx))
return bfd_r_type;
abfd = stub_entry->target_section->owner;
if (!aarch64_valid_branch_p (veneer_entry_loc, veneered_insn_loc))
- (*_bfd_error_handler)
- (_("%B: error: Erratum 835769 stub out "
- "of range (input file too large)"), abfd);
+ _bfd_error_handler
+ (_("%pB: error: erratum 835769 stub out "
+ "of range (input file too large)"), abfd);
target = stub_entry->target_value;
branch_insn = 0x14000000;
+ stub_entry->adrp_offset);
insn = bfd_getl32 (contents + stub_entry->adrp_offset);
- if ((insn & AARCH64_ADRP_OP_MASK) != AARCH64_ADRP_OP)
+ if (!_bfd_aarch64_adrp_p (insn))
abort ();
bfd_signed_vma imm =
abfd = stub_entry->target_section->owner;
if (!aarch64_valid_branch_p (veneer_entry_loc, veneered_insn_loc))
- (*_bfd_error_handler)
- (_("%B: error: Erratum 843419 stub out "
+ _bfd_error_handler
+ (_("%pB: error: erratum 843419 stub out "
"of range (input file too large)"), abfd);
branch_insn = 0x14000000;
return FALSE;
}
-/* Perform a relocation as part of a final link. */
+/* Return TRUE if RELOC is a relocation against the base of GOT table. */
+
+static bfd_boolean
+aarch64_relocation_aginst_gp_p (bfd_reloc_code_real_type reloc)
+{
+ return (reloc == BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14
+ || reloc == BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15
+ || reloc == BFD_RELOC_AARCH64_LD64_GOTOFF_LO15
+ || reloc == BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC
+ || reloc == BFD_RELOC_AARCH64_MOVW_GOTOFF_G1);
+}
+
+/* Perform a relocation as part of a final link. The input relocation type
+ should be TLS relaxed. */
+
static bfd_reloc_status_type
elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
bfd *input_bfd,
unsigned int r_type = howto->type;
bfd_reloc_code_real_type bfd_r_type
= elfNN_aarch64_bfd_reloc_from_howto (howto);
- bfd_reloc_code_real_type new_bfd_r_type;
unsigned long r_symndx;
bfd_byte *hit_data = contents + rel->r_offset;
- bfd_vma place, off;
+ bfd_vma place, off, got_entry_addr = 0;
bfd_signed_vma signed_addend;
struct elf_aarch64_link_hash_table *globals;
bfd_boolean weak_undef_p;
+ bfd_boolean relative_reloc;
asection *base_got;
+ bfd_vma orig_value = value;
+ bfd_boolean resolved_to_zero;
+ bfd_boolean abs_symbol_p;
globals = elf_aarch64_hash_table (info);
r_symndx = ELFNN_R_SYM (rel->r_info);
- /* It is possible to have linker relaxations on some TLS access
- models. Update our information here. */
- new_bfd_r_type = aarch64_tls_transition (input_bfd, info, r_type, h, r_symndx);
- if (new_bfd_r_type != bfd_r_type)
- {
- bfd_r_type = new_bfd_r_type;
- howto = elfNN_aarch64_howto_from_bfd_reloc (bfd_r_type);
- BFD_ASSERT (howto != NULL);
- r_type = howto->type;
- }
-
place = input_section->output_section->vma
+ input_section->output_offset + rel->r_offset;
weak_undef_p = (h ? h->root.type == bfd_link_hash_undefweak
: bfd_is_und_section (sym_sec));
+ abs_symbol_p = h != NULL && bfd_is_abs_symbol (&h->root);
+
/* Since STT_GNU_IFUNC symbol must go through PLT, we handle
it here if it is defined in a non-shared object. */
const char *name;
bfd_vma addend = 0;
- if ((input_section->flags & SEC_ALLOC) == 0
- || h->plt.offset == (bfd_vma) -1)
- abort ();
+ if ((input_section->flags & SEC_ALLOC) == 0)
+ {
+ /* If this is a SHT_NOTE section without SHF_ALLOC, treat
+ STT_GNU_IFUNC symbol as STT_FUNC. */
+ if (elf_section_type (input_section) == SHT_NOTE)
+ goto skip_ifunc;
+
+ /* Dynamic relocs are not propagated for SEC_DEBUGGING
+ sections because such sections are not SEC_ALLOC and
+ thus ld.so will not process them. */
+ if ((input_section->flags & SEC_DEBUGGING) != 0)
+ return bfd_reloc_ok;
+
+ if (h->root.root.string)
+ name = h->root.root.string;
+ else
+ name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, NULL);
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA+%#" PRIx64 "): "
+ "unresolvable %s relocation against symbol `%s'"),
+ input_bfd, input_section, (uint64_t) rel->r_offset,
+ howto->name, name);
+ bfd_set_error (bfd_error_bad_value);
+ return bfd_reloc_notsupported;
+ }
+ else if (h->plt.offset == (bfd_vma) -1)
+ goto bad_ifunc_reloc;
/* STT_GNU_IFUNC symbol must go through PLT. */
plt = globals->root.splt ? globals->root.splt : globals->root.iplt;
switch (bfd_r_type)
{
default:
+bad_ifunc_reloc:
if (h->root.root.string)
name = h->root.root.string;
else
name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym,
NULL);
- (*_bfd_error_handler)
- (_("%B: relocation %s against STT_GNU_IFUNC "
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: relocation %s against STT_GNU_IFUNC "
"symbol `%s' isn't handled by %s"), input_bfd,
howto->name, name, __FUNCTION__);
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return bfd_reloc_notsupported;
case BFD_RELOC_AARCH64_NN:
if (rel->r_addend != 0)
else
name = bfd_elf_sym_name (input_bfd, symtab_hdr,
sym, NULL);
- (*_bfd_error_handler)
- (_("%B: relocation %s against STT_GNU_IFUNC "
- "symbol `%s' has non-zero addend: %d"),
- input_bfd, howto->name, name, rel->r_addend);
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: relocation %s against STT_GNU_IFUNC "
+ "symbol `%s' has non-zero addend: %" PRId64),
+ input_bfd, howto->name, name, (int64_t) rel->r_addend);
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return bfd_reloc_notsupported;
}
/* Generate dynamic relocation only when there is a
value, output_bfd,
unresolved_reloc_p);
- switch (bfd_r_type)
- {
- case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14:
- case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15:
- addend = (globals->root.sgot->output_section->vma
- + globals->root.sgot->output_offset);
- break;
- case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC:
- case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1:
- case BFD_RELOC_AARCH64_LD64_GOTOFF_LO15:
- value = (value - globals->root.sgot->output_section->vma
- - globals->root.sgot->output_offset);
- default:
- break;
- }
+ if (aarch64_relocation_aginst_gp_p (bfd_r_type))
+ addend = (globals->root.sgot->output_section->vma
+ + globals->root.sgot->output_offset);
value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value,
addend, weak_undef_p);
}
}
+ skip_ifunc:
+ resolved_to_zero = (h != NULL
+ && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h));
+
switch (bfd_r_type)
{
case BFD_RELOC_AARCH64_NONE:
+ case BFD_RELOC_AARCH64_TLSDESC_ADD:
case BFD_RELOC_AARCH64_TLSDESC_CALL:
+ case BFD_RELOC_AARCH64_TLSDESC_LDR:
*unresolved_reloc_p = FALSE;
return bfd_reloc_ok;
case BFD_RELOC_AARCH64_NN:
/* When generating a shared object or relocatable executable, these
- relocations are copied into the output file to be resolved at
- run time. */
- if (((bfd_link_pic (info) == TRUE)
- || globals->root.is_relocatable_executable)
- && (input_section->flags & SEC_ALLOC)
- && (h == NULL
- || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
- || h->root.type != bfd_link_hash_undefweak))
+ relocations are copied into the output file to be resolved at
+ run time. */
+ if (((bfd_link_pic (info)
+ || globals->root.is_relocatable_executable)
+ && (input_section->flags & SEC_ALLOC)
+ && (h == NULL
+ || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ && !resolved_to_zero)
+ || h->root.type != bfd_link_hash_undefweak))
+ /* Or we are creating an executable, we may need to keep relocations
+ for symbols satisfied by a dynamic library if we manage to avoid
+ copy relocs for the symbol. */
+ || (ELIMINATE_COPY_RELOCS
+ && !bfd_link_pic (info)
+ && h != NULL
+ && (input_section->flags & SEC_ALLOC)
+ && h->dynindx != -1
+ && !h->non_got_ref
+ && ((h->def_dynamic
+ && !h->def_regular)
+ || h->root.type == bfd_link_hash_undefweak
+ || h->root.type == bfd_link_hash_undefined)))
{
Elf_Internal_Rela outrel;
bfd_byte *loc;
skip = TRUE;
relocate = TRUE;
}
+ else if (abs_symbol_p)
+ {
+ /* Local absolute symbol. */
+ skip = (h->forced_local || (h->dynindx == -1));
+ relocate = skip;
+ }
outrel.r_offset += (input_section->output_section->vma
+ input_section->output_offset);
else if (h != NULL
&& h->dynindx != -1
&& (!bfd_link_pic (info)
- || !SYMBOLIC_BIND (info, h)
+ || !(bfd_link_pie (info) || SYMBOLIC_BIND (info, h))
|| !h->def_regular))
outrel.r_info = ELFNN_R_INFO (h->dynindx, r_type);
else
relocate the text and data segments independently,
so the symbol does not matter. */
symbol = 0;
+ relocate = globals->no_apply_dynamic_relocs ? FALSE : TRUE;
outrel.r_info = ELFNN_R_INFO (symbol, AARCH64_R (RELATIVE));
outrel.r_addend += value;
}
/* Check if a stub has to be inserted because the destination
is too far away. */
struct elf_aarch64_stub_hash_entry *stub_entry = NULL;
- if (! aarch64_valid_branch_p (value, place))
+
+ /* If the branch destination is directed to plt stub, "value" will be
+ the final destination, otherwise we should plus signed_addend, it may
+ contain non-zero value, for example call to local function symbol
+ which are turned into "sec_sym + sec_off", and sec_off is kept in
+ signed_addend. */
+ if (! aarch64_valid_branch_p (via_plt_p ? value : value + signed_addend,
+ place))
/* The target is out of reach, so redirect the branch to
the local stub for this function. */
stub_entry = elfNN_aarch64_get_stub_entry (input_section, sym_sec, h,
rel, globals);
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);
+
+ /* We have redirected the destination to stub entry address,
+ so ignore any addend record in the original rela entry. */
+ signed_addend = 0;
+ }
}
value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value,
signed_addend, weak_undef_p);
case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
case BFD_RELOC_AARCH64_ADR_LO21_PCREL:
case BFD_RELOC_AARCH64_LD_LO19_PCREL:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G0:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G0_NC:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G1:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G1_NC:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G2:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G2_NC:
+ case BFD_RELOC_AARCH64_MOVW_PREL_G3:
if (bfd_link_pic (info)
&& (input_section->flags & SEC_ALLOC) != 0
&& (input_section->flags & SEC_READONLY) != 0
- && h != NULL
- && !h->def_regular)
+ && !SYMBOL_REFERENCES_LOCAL (info, h))
{
int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START;
- (*_bfd_error_handler)
- (_("%B: relocation %s against external symbol `%s' can not be used"
- " when making a shared object; recompile with -fPIC"),
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: relocation %s against symbol `%s' which may bind "
+ "externally can not be used when making a shared object; "
+ "recompile with -fPIC"),
input_bfd, elfNN_aarch64_howto_table[howto_index].name,
h->root.root.string);
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return bfd_reloc_notsupported;
}
+ /* Fall through. */
case BFD_RELOC_AARCH64_16:
#if ARCH_SIZE == 64
case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15:
case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
+ case BFD_RELOC_AARCH64_LD64_GOTOFF_LO15:
+ case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC:
+ case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1:
if (globals->root.sgot == NULL)
BFD_ASSERT (h != NULL);
+ relative_reloc = FALSE;
if (h != NULL)
{
bfd_vma addend = 0;
+
+ /* If a symbol is not dynamic and is not undefined weak, bind it
+ locally and generate a RELATIVE relocation under PIC mode.
+
+ NOTE: one symbol may be referenced by several relocations, we
+ should only generate one RELATIVE relocation for that symbol.
+ Therefore, check GOT offset mark first. */
+ if (h->dynindx == -1
+ && !h->forced_local
+ && h->root.type != bfd_link_hash_undefweak
+ && bfd_link_pic (info)
+ && !symbol_got_offset_mark_p (input_bfd, h, r_symndx))
+ relative_reloc = TRUE;
+
value = aarch64_calculate_got_entry_vma (h, globals, info, value,
output_bfd,
unresolved_reloc_p);
- if (bfd_r_type == BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15
- || bfd_r_type == BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14)
+ /* Record the GOT entry address which will be used when generating
+ RELATIVE relocation. */
+ if (relative_reloc)
+ got_entry_addr = value;
+
+ if (aarch64_relocation_aginst_gp_p (bfd_r_type))
addend = (globals->root.sgot->output_section->vma
+ globals->root.sgot->output_offset);
value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value,
if (locals == NULL)
{
int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START;
- (*_bfd_error_handler)
- (_("%B: Local symbol descriptor table be NULL when applying "
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: local symbol descriptor table be NULL when applying "
"relocation %s against local symbol"),
input_bfd, elfNN_aarch64_howto_table[howto_index].name);
abort ();
off = symbol_got_offset (input_bfd, h, r_symndx);
base_got = globals->root.sgot;
- bfd_vma got_entry_addr = (base_got->output_section->vma
- + base_got->output_offset + off);
+ got_entry_addr = (base_got->output_section->vma
+ + base_got->output_offset + off);
if (!symbol_got_offset_mark_p (input_bfd, h, r_symndx))
{
bfd_put_64 (output_bfd, value, base_got->contents + off);
+ /* For local symbol, we have done absolute relocation in static
+ linking stage. While for shared library, we need to update the
+ content of GOT entry according to the shared object's runtime
+ base address. So, we need to generate a R_AARCH64_RELATIVE reloc
+ for dynamic linker. */
if (bfd_link_pic (info))
- {
- asection *s;
- Elf_Internal_Rela outrel;
-
- /* For local symbol, we have done absolute relocation in static
- linking stageh. While for share library, we need to update
- the content of GOT entry according to the share objects
- loading base address. So we need to generate a
- R_AARCH64_RELATIVE reloc for dynamic linker. */
- s = globals->root.srelgot;
- if (s == NULL)
- abort ();
-
- outrel.r_offset = got_entry_addr;
- outrel.r_info = ELFNN_R_INFO (0, AARCH64_R (RELATIVE));
- outrel.r_addend = value;
- elf_append_rela (output_bfd, s, &outrel);
- }
+ relative_reloc = TRUE;
symbol_got_offset_mark (input_bfd, h, r_symndx);
}
the direct data access into indirect data access through GOT. */
value = got_entry_addr;
- if (bfd_r_type == BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15
- || bfd_r_type == BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14)
+ if (aarch64_relocation_aginst_gp_p (bfd_r_type))
addend = base_got->output_section->vma + base_got->output_offset;
value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value,
addend, weak_undef_p);
}
- break;
+ if (relative_reloc)
+ {
+ asection *s;
+ Elf_Internal_Rela outrel;
- case BFD_RELOC_AARCH64_LD64_GOTOFF_LO15:
- case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC:
- case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1:
- if (h != NULL)
- value = aarch64_calculate_got_entry_vma (h, globals, info, value,
- output_bfd,
- unresolved_reloc_p);
- else
- {
- struct elf_aarch64_local_symbol *locals
- = elf_aarch64_locals (input_bfd);
-
- if (locals == NULL)
- {
- int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START;
- (*_bfd_error_handler)
- (_("%B: Local symbol descriptor table be NULL when applying "
- "relocation %s against local symbol"),
- input_bfd, elfNN_aarch64_howto_table[howto_index].name);
- abort ();
- }
-
- off = symbol_got_offset (input_bfd, h, r_symndx);
- base_got = globals->root.sgot;
- if (base_got == NULL)
+ s = globals->root.srelgot;
+ if (s == NULL)
abort ();
- bfd_vma got_entry_addr = (base_got->output_section->vma
- + base_got->output_offset + off);
-
- if (!symbol_got_offset_mark_p (input_bfd, h, r_symndx))
- {
- bfd_put_64 (output_bfd, value, base_got->contents + off);
-
- if (bfd_link_pic (info))
- {
- asection *s;
- Elf_Internal_Rela outrel;
-
- /* For local symbol, we have done absolute relocation in static
- linking stage. While for share library, we need to update
- the content of GOT entry according to the share objects
- loading base address. So we need to generate a
- R_AARCH64_RELATIVE reloc for dynamic linker. */
- s = globals->root.srelgot;
- if (s == NULL)
- abort ();
-
- outrel.r_offset = got_entry_addr;
- outrel.r_info = ELFNN_R_INFO (0, AARCH64_R (RELATIVE));
- outrel.r_addend = value;
- elf_append_rela (output_bfd, s, &outrel);
- }
-
- symbol_got_offset_mark (input_bfd, h, r_symndx);
- }
+ outrel.r_offset = got_entry_addr;
+ outrel.r_info = ELFNN_R_INFO (0, AARCH64_R (RELATIVE));
+ outrel.r_addend = orig_value;
+ elf_append_rela (output_bfd, s, &outrel);
}
-
- /* Update the relocation value to GOT entry addr as we have transformed
- the direct data access into indirect data access through GOT. */
- value = symbol_got_offset (input_bfd, h, r_symndx);
- value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value,
- 0, weak_undef_p);
- *unresolved_reloc_p = FALSE;
break;
case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC:
case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12:
case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12:
case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0:
case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1:
*unresolved_reloc_p = FALSE;
break;
- case BFD_RELOC_AARCH64_TLSDESC_ADD:
- case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12:
case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21:
case BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21:
case BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC:
- case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC:
- case BFD_RELOC_AARCH64_TLSDESC_LDR:
+ case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12:
case BFD_RELOC_AARCH64_TLSDESC_LD_PREL19:
if (globals->root.sgot == NULL)
return bfd_reloc_notsupported;
*unresolved_reloc_p = FALSE;
break;
+ case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC:
+ case BFD_RELOC_AARCH64_TLSDESC_OFF_G1:
+ if (globals->root.sgot == NULL)
+ return bfd_reloc_notsupported;
+
+ value = (symbol_tlsdesc_got_offset (input_bfd, h, r_symndx)
+ + globals->root.sgotplt->output_section->vma
+ + globals->root.sgotplt->output_offset
+ + globals->sgotplt_jump_table_size);
+
+ value -= (globals->root.sgot->output_section->vma
+ + globals->root.sgot->output_offset);
+
+ value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value,
+ 0, weak_undef_p);
+ *unresolved_reloc_p = FALSE;
+ break;
+
default:
return bfd_reloc_notsupported;
}
howto, value);
}
+/* LP64 and ILP32 operates on x- and w-registers respectively.
+ Next definitions take into account the difference between
+ corresponding machine codes. R means x-register if the target
+ arch is LP64, and w-register if the target is ILP32. */
+
+#if ARCH_SIZE == 64
+# define add_R0_R0 (0x91000000)
+# define add_R0_R0_R1 (0x8b000020)
+# define add_R0_R1 (0x91400020)
+# define ldr_R0 (0x58000000)
+# define ldr_R0_mask(i) (i & 0xffffffe0)
+# define ldr_R0_x0 (0xf9400000)
+# define ldr_hw_R0 (0xf2a00000)
+# define movk_R0 (0xf2800000)
+# define movz_R0 (0xd2a00000)
+# define movz_hw_R0 (0xd2c00000)
+#else /*ARCH_SIZE == 32 */
+# define add_R0_R0 (0x11000000)
+# define add_R0_R0_R1 (0x0b000020)
+# define add_R0_R1 (0x11400020)
+# define ldr_R0 (0x18000000)
+# define ldr_R0_mask(i) (i & 0xbfffffe0)
+# define ldr_R0_x0 (0xb9400000)
+# define ldr_hw_R0 (0x72a00000)
+# define movk_R0 (0x72800000)
+# define movz_R0 (0x52a00000)
+# define movz_hw_R0 (0x52c00000)
+#endif
+
+/* Structure to hold payload for _bfd_aarch64_erratum_843419_clear_stub,
+ it is used to identify the stub information to reset. */
+
+struct erratum_843419_branch_to_stub_clear_data
+{
+ bfd_vma adrp_offset;
+ asection *output_section;
+};
+
+/* Clear the erratum information for GEN_ENTRY if the ADRP_OFFSET and
+ section inside IN_ARG matches. The clearing is done by setting the
+ stub_type to none. */
+
+static bfd_boolean
+_bfd_aarch64_erratum_843419_clear_stub (struct bfd_hash_entry *gen_entry,
+ void *in_arg)
+{
+ struct elf_aarch64_stub_hash_entry *stub_entry
+ = (struct elf_aarch64_stub_hash_entry *) gen_entry;
+ struct erratum_843419_branch_to_stub_clear_data *data
+ = (struct erratum_843419_branch_to_stub_clear_data *) in_arg;
+
+ if (stub_entry->target_section != data->output_section
+ || stub_entry->stub_type != aarch64_stub_erratum_843419_veneer
+ || stub_entry->adrp_offset != data->adrp_offset)
+ return TRUE;
+
+ /* Change the stub type instead of removing the entry, removing from the hash
+ table would be slower and we have already reserved the memory for the entry
+ so there wouldn't be much gain. Changing the stub also keeps around a
+ record of what was there before. */
+ stub_entry->stub_type = aarch64_stub_none;
+
+ /* We're done and there could have been only one matching stub at that
+ particular offset, so abort further traversal. */
+ return FALSE;
+}
+
+/* TLS Relaxations may relax an adrp sequence that matches the erratum 843419
+ sequence. In this case the erratum no longer applies and we need to remove
+ the entry from the pending stub generation. This clears matching adrp insn
+ at ADRP_OFFSET in INPUT_SECTION in the stub table defined in GLOBALS. */
+
+static void
+clear_erratum_843419_entry (struct elf_aarch64_link_hash_table *globals,
+ bfd_vma adrp_offset, asection *input_section)
+{
+ if (globals->fix_erratum_843419)
+ {
+ struct erratum_843419_branch_to_stub_clear_data data;
+ data.adrp_offset = adrp_offset;
+ data.output_section = input_section;
+
+ bfd_hash_traverse (&globals->stub_hash_table,
+ _bfd_aarch64_erratum_843419_clear_stub, &data);
+ }
+}
+
/* Handle TLS relaxations. Relaxing is possible for symbols that use
R_AARCH64_TLSDESC_ADR_{PAGE, LD64_LO12_NC, ADD_LO12_NC} during a static
link.
static bfd_reloc_status_type
elfNN_aarch64_tls_relax (struct elf_aarch64_link_hash_table *globals,
- bfd *input_bfd, bfd_byte *contents,
- Elf_Internal_Rela *rel, struct elf_link_hash_entry *h)
+ bfd *input_bfd, asection *input_section,
+ bfd_byte *contents, Elf_Internal_Rela *rel,
+ struct elf_link_hash_entry *h)
{
bfd_boolean is_local = h == NULL;
unsigned int r_type = ELFNN_R_TYPE (rel->r_info);
BFD_ASSERT (globals && input_bfd && contents && rel);
- switch (elfNN_aarch64_bfd_reloc_from_type (r_type))
+ switch (elfNN_aarch64_bfd_reloc_from_type (input_bfd, r_type))
{
case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21:
case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21:
if (is_local)
{
/* GD->LE relaxation:
- adrp x0, :tlsgd:var => movz x0, :tprel_g1:var
+ adrp x0, :tlsgd:var => movz R0, :tprel_g1:var
or
- adrp x0, :tlsdesc:var => movz x0, :tprel_g1:var
- */
- bfd_putl32 (0xd2a00000, contents + rel->r_offset);
+ adrp x0, :tlsdesc:var => movz R0, :tprel_g1:var
+
+ Where R is x for LP64, and w for ILP32. */
+ bfd_putl32 (movz_R0, contents + rel->r_offset);
+ /* We have relaxed the adrp into a mov, we may have to clear any
+ pending erratum fixes. */
+ clear_erratum_843419_entry (globals, rel->r_offset, input_section);
return bfd_reloc_continue;
}
else
if (is_local)
{
/* Tiny TLSDESC->LE relaxation:
- ldr x1, :tlsdesc:var => movz x0, #:tprel_g1:var
- adr x0, :tlsdesc:var => movk x0, #:tprel_g0_nc:var
+ ldr x1, :tlsdesc:var => movz R0, #:tprel_g1:var
+ adr x0, :tlsdesc:var => movk R0, #:tprel_g0_nc:var
.tlsdesccall var
- blr x1 => nop
- */
+ blr x1 => nop
+
+ Where R is x for LP64, and w for ILP32. */
BFD_ASSERT (ELFNN_R_TYPE (rel[1].r_info) == AARCH64_R (TLSDESC_ADR_PREL21));
BFD_ASSERT (ELFNN_R_TYPE (rel[2].r_info) == AARCH64_R (TLSDESC_CALL));
AARCH64_R (TLSLE_MOVW_TPREL_G0_NC));
rel[2].r_info = ELFNN_R_INFO (STN_UNDEF, R_AARCH64_NONE);
- bfd_putl32 (0xd2a00000, contents + rel->r_offset);
- bfd_putl32 (0xf2800000, contents + rel->r_offset + 4);
+ bfd_putl32 (movz_R0, contents + rel->r_offset);
+ bfd_putl32 (movk_R0, contents + rel->r_offset + 4);
bfd_putl32 (INSN_NOP, contents + rel->r_offset + 8);
return bfd_reloc_continue;
}
else
{
/* Tiny TLSDESC->IE relaxation:
- ldr x1, :tlsdesc:var => ldr x0, :gottprel:var
- adr x0, :tlsdesc:var => nop
+ ldr x1, :tlsdesc:var => ldr x0, :gottprel:var
+ adr x0, :tlsdesc:var => nop
.tlsdesccall var
- blr x1 => nop
+ blr x1 => nop
*/
BFD_ASSERT (ELFNN_R_TYPE (rel[1].r_info) == AARCH64_R (TLSDESC_ADR_PREL21));
BFD_ASSERT (ELFNN_R_TYPE (rel[2].r_info) == AARCH64_R (TLSDESC_CALL));
rel[1].r_info = ELFNN_R_INFO (STN_UNDEF, R_AARCH64_NONE);
rel[2].r_info = ELFNN_R_INFO (STN_UNDEF, R_AARCH64_NONE);
- bfd_putl32 (0x58000000, contents + rel->r_offset);
+ bfd_putl32 (ldr_R0, contents + rel->r_offset);
bfd_putl32 (INSN_NOP, contents + rel->r_offset + 4);
bfd_putl32 (INSN_NOP, contents + rel->r_offset + 8);
return bfd_reloc_continue;
if (is_local)
{
/* Tiny GD->LE relaxation:
- adr x0, :tlsgd:var => mrs x1, tpidr_el0
- bl __tls_get_addr => add x0, x1, #:tprel_hi12:x, lsl #12
- nop => add x0, x0, #:tprel_lo12_nc:x
- */
+ adr x0, :tlsgd:var => mrs x1, tpidr_el0
+ bl __tls_get_addr => add R0, R1, #:tprel_hi12:x, lsl #12
+ nop => add R0, R0, #:tprel_lo12_nc:x
+
+ Where R is x for LP64, and x for Ilp32. */
/* First kill the tls_get_addr reloc on the bl instruction. */
BFD_ASSERT (rel->r_offset + 4 == rel[1].r_offset);
bfd_putl32 (0xd53bd041, contents + rel->r_offset + 0);
- bfd_putl32 (0x91400020, contents + rel->r_offset + 4);
- bfd_putl32 (0x91000000, contents + rel->r_offset + 8);
+ bfd_putl32 (add_R0_R1, contents + rel->r_offset + 4);
+ bfd_putl32 (add_R0_R0, contents + rel->r_offset + 8);
rel[1].r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel->r_info),
AARCH64_R (TLSLE_ADD_TPREL_LO12_NC));
else
{
/* Tiny GD->IE relaxation:
- adr x0, :tlsgd:var => ldr x0, :gottprel:var
- bl __tls_get_addr => mrs x1, tpidr_el0
- nop => add x0, x0, x1
- */
+ adr x0, :tlsgd:var => ldr R0, :gottprel:var
+ bl __tls_get_addr => mrs x1, tpidr_el0
+ nop => add R0, R0, R1
+
+ Where R is x for LP64, and w for Ilp32. */
/* First kill the tls_get_addr reloc on the bl instruction. */
BFD_ASSERT (rel->r_offset + 4 == rel[1].r_offset);
rel[1].r_info = ELFNN_R_INFO (STN_UNDEF, R_AARCH64_NONE);
- bfd_putl32 (0x58000000, contents + rel->r_offset);
+ bfd_putl32 (ldr_R0, contents + rel->r_offset);
bfd_putl32 (0xd53bd041, contents + rel->r_offset + 4);
- bfd_putl32 (0x8b000020, contents + rel->r_offset + 8);
+ bfd_putl32 (add_R0_R0_R1, contents + rel->r_offset + 8);
return bfd_reloc_continue;
}
+#if ARCH_SIZE == 64
+ case BFD_RELOC_AARCH64_TLSGD_MOVW_G1:
+ BFD_ASSERT (ELFNN_R_TYPE (rel[1].r_info) == AARCH64_R (TLSGD_MOVW_G0_NC));
+ BFD_ASSERT (rel->r_offset + 12 == rel[2].r_offset);
+ BFD_ASSERT (ELFNN_R_TYPE (rel[2].r_info) == AARCH64_R (CALL26));
+
+ if (is_local)
+ {
+ /* Large GD->LE relaxation:
+ movz x0, #:tlsgd_g1:var => movz x0, #:tprel_g2:var, lsl #32
+ movk x0, #:tlsgd_g0_nc:var => movk x0, #:tprel_g1_nc:var, lsl #16
+ add x0, gp, x0 => movk x0, #:tprel_g0_nc:var
+ bl __tls_get_addr => mrs x1, tpidr_el0
+ nop => add x0, x0, x1
+ */
+ rel[2].r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel->r_info),
+ AARCH64_R (TLSLE_MOVW_TPREL_G0_NC));
+ rel[2].r_offset = rel->r_offset + 8;
+
+ bfd_putl32 (movz_hw_R0, contents + rel->r_offset + 0);
+ bfd_putl32 (ldr_hw_R0, contents + rel->r_offset + 4);
+ bfd_putl32 (movk_R0, contents + rel->r_offset + 8);
+ bfd_putl32 (0xd53bd041, contents + rel->r_offset + 12);
+ bfd_putl32 (add_R0_R0_R1, contents + rel->r_offset + 16);
+ }
+ else
+ {
+ /* Large GD->IE relaxation:
+ movz x0, #:tlsgd_g1:var => movz x0, #:gottprel_g1:var, lsl #16
+ movk x0, #:tlsgd_g0_nc:var => movk x0, #:gottprel_g0_nc:var
+ add x0, gp, x0 => ldr x0, [gp, x0]
+ bl __tls_get_addr => mrs x1, tpidr_el0
+ nop => add x0, x0, x1
+ */
+ rel[2].r_info = ELFNN_R_INFO (STN_UNDEF, R_AARCH64_NONE);
+ bfd_putl32 (0xd2a80000, contents + rel->r_offset + 0);
+ bfd_putl32 (ldr_R0, contents + rel->r_offset + 8);
+ bfd_putl32 (0xd53bd041, contents + rel->r_offset + 12);
+ bfd_putl32 (add_R0_R0_R1, contents + rel->r_offset + 16);
+ }
+ return bfd_reloc_continue;
+
+ case BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC:
+ return bfd_reloc_continue;
+#endif
+
case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19:
return bfd_reloc_continue;
{
/* GD->LE relaxation:
ldr xd, [x0, #:tlsdesc_lo12:var] => movk x0, :tprel_g0_nc:var
- */
- bfd_putl32 (0xf2800000, contents + rel->r_offset);
+
+ Where R is x for lp64 mode, and w for ILP32 mode. */
+ bfd_putl32 (movk_R0, contents + rel->r_offset);
return bfd_reloc_continue;
}
else
{
/* GD->IE relaxation:
- ldr xd, [x0, #:tlsdesc_lo12:var] => ldr x0, [x0, #:gottprel_lo12:var]
- */
+ ldr xd, [x0, #:tlsdesc_lo12:var] => ldr R0, [x0, #:gottprel_lo12:var]
+
+ Where R is x for lp64 mode, and w for ILP32 mode. */
insn = bfd_getl32 (contents + rel->r_offset);
- insn &= 0xffffffe0;
- bfd_putl32 (insn, contents + rel->r_offset);
+ bfd_putl32 (ldr_R0_mask (insn), contents + rel->r_offset);
return bfd_reloc_continue;
}
if (is_local)
{
/* GD->LE relaxation
- add x0, #:tlsgd_lo12:var => movk x0, :tprel_g0_nc:var
- bl __tls_get_addr => mrs x1, tpidr_el0
- nop => add x0, x1, x0
- */
+ add x0, #:tlsgd_lo12:var => movk R0, :tprel_g0_nc:var
+ bl __tls_get_addr => mrs x1, tpidr_el0
+ nop => add R0, R1, R0
+
+ Where R is x for lp64 mode, and w for ILP32 mode. */
/* First kill the tls_get_addr reloc on the bl instruction. */
BFD_ASSERT (rel->r_offset + 4 == rel[1].r_offset);
rel[1].r_info = ELFNN_R_INFO (STN_UNDEF, R_AARCH64_NONE);
- bfd_putl32 (0xf2800000, contents + rel->r_offset);
+ bfd_putl32 (movk_R0, contents + rel->r_offset);
bfd_putl32 (0xd53bd041, contents + rel->r_offset + 4);
- bfd_putl32 (0x8b000020, contents + rel->r_offset + 8);
+ bfd_putl32 (add_R0_R0_R1, contents + rel->r_offset + 8);
return bfd_reloc_continue;
}
else
{
/* GD->IE relaxation
- ADD x0, #:tlsgd_lo12:var => ldr x0, [x0, #:gottprel_lo12:var]
- BL __tls_get_addr => mrs x1, tpidr_el0
+ ADD x0, #:tlsgd_lo12:var => ldr R0, [x0, #:gottprel_lo12:var]
+ BL __tls_get_addr => mrs x1, tpidr_el0
R_AARCH64_CALL26
- NOP => add x0, x1, x0
- */
+ NOP => add R0, R1, R0
+
+ Where R is x for lp64 mode, and w for ilp32 mode. */
BFD_ASSERT (ELFNN_R_TYPE (rel[1].r_info) == AARCH64_R (CALL26));
/* Remove the relocation on the BL instruction. */
rel[1].r_info = ELFNN_R_INFO (STN_UNDEF, R_AARCH64_NONE);
- bfd_putl32 (0xf9400000, contents + rel->r_offset);
-
/* We choose to fixup the BL and NOP instructions using the
offset from the second relocation to allow flexibility in
scheduling instructions between the ADD and BL. */
+ bfd_putl32 (ldr_R0_x0, contents + rel->r_offset);
bfd_putl32 (0xd53bd041, contents + rel[1].r_offset);
- bfd_putl32 (0x8b000020, contents + rel[1].r_offset + 4);
+ bfd_putl32 (add_R0_R0_R1, contents + rel[1].r_offset + 4);
return bfd_reloc_continue;
}
- case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSDESC_ADD:
+ case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12:
case BFD_RELOC_AARCH64_TLSDESC_CALL:
/* GD->IE/LE relaxation:
- add x0, x0, #:tlsdesc_lo12:var => nop
- blr xd => nop
+ add x0, x0, #:tlsdesc_lo12:var => nop
+ blr xd => nop
*/
bfd_putl32 (INSN_NOP, contents + rel->r_offset);
return bfd_reloc_ok;
+ case BFD_RELOC_AARCH64_TLSDESC_LDR:
+ if (is_local)
+ {
+ /* GD->LE relaxation:
+ ldr xd, [gp, xn] => movk R0, #:tprel_g0_nc:var
+
+ Where R is x for lp64 mode, and w for ILP32 mode. */
+ bfd_putl32 (movk_R0, contents + rel->r_offset);
+ return bfd_reloc_continue;
+ }
+ else
+ {
+ /* GD->IE relaxation:
+ ldr xd, [gp, xn] => ldr R0, [gp, xn]
+
+ Where R is x for lp64 mode, and w for ILP32 mode. */
+ insn = bfd_getl32 (contents + rel->r_offset);
+ bfd_putl32 (ldr_R0_mask (insn), contents + rel->r_offset);
+ return bfd_reloc_ok;
+ }
+
+ case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC:
+ /* GD->LE relaxation:
+ movk xd, #:tlsdesc_off_g0_nc:var => movk R0, #:tprel_g1_nc:var, lsl #16
+ GD->IE relaxation:
+ movk xd, #:tlsdesc_off_g0_nc:var => movk Rd, #:gottprel_g0_nc:var
+
+ Where R is x for lp64 mode, and w for ILP32 mode. */
+ if (is_local)
+ bfd_putl32 (ldr_hw_R0, contents + rel->r_offset);
+ return bfd_reloc_continue;
+
+ case BFD_RELOC_AARCH64_TLSDESC_OFF_G1:
+ if (is_local)
+ {
+ /* GD->LE relaxation:
+ movz xd, #:tlsdesc_off_g1:var => movz R0, #:tprel_g2:var, lsl #32
+
+ Where R is x for lp64 mode, and w for ILP32 mode. */
+ bfd_putl32 (movz_hw_R0, contents + rel->r_offset);
+ return bfd_reloc_continue;
+ }
+ else
+ {
+ /* GD->IE relaxation:
+ movz xd, #:tlsdesc_off_g1:var => movz Rd, #:gottprel_g1:var, lsl #16
+
+ Where R is x for lp64 mode, and w for ILP32 mode. */
+ insn = bfd_getl32 (contents + rel->r_offset);
+ bfd_putl32 (movz_R0 | (insn & 0x1f), contents + rel->r_offset);
+ return bfd_reloc_continue;
+ }
+
case BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
/* IE->LE relaxation:
- adrp xd, :gottprel:var => movz xd, :tprel_g1:var
- */
+ adrp xd, :gottprel:var => movz Rd, :tprel_g1:var
+
+ Where R is x for lp64 mode, and w for ILP32 mode. */
if (is_local)
{
insn = bfd_getl32 (contents + rel->r_offset);
- bfd_putl32 (0xd2a00000 | (insn & 0x1f), contents + rel->r_offset);
+ bfd_putl32 (movz_R0 | (insn & 0x1f), contents + rel->r_offset);
+ /* We have relaxed the adrp into a mov, we may have to clear any
+ pending erratum fixes. */
+ clear_erratum_843419_entry (globals, rel->r_offset, input_section);
}
return bfd_reloc_continue;
case BFD_RELOC_AARCH64_TLSIE_LDNN_GOTTPREL_LO12_NC:
/* IE->LE relaxation:
- ldr xd, [xm, #:gottprel_lo12:var] => movk xd, :tprel_g0_nc:var
- */
+ ldr xd, [xm, #:gottprel_lo12:var] => movk Rd, :tprel_g0_nc:var
+
+ Where R is x for lp64 mode, and w for ILP32 mode. */
if (is_local)
{
insn = bfd_getl32 (contents + rel->r_offset);
- bfd_putl32 (0xf2800000 | (insn & 0x1f), contents + rel->r_offset);
+ bfd_putl32 (movk_R0 | (insn & 0x1f), contents + rel->r_offset);
}
return bfd_reloc_continue;
case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21:
/* LD->LE relaxation (tiny):
adr x0, :tlsldm:x => mrs x0, tpidr_el0
- bl __tls_get_addr => add x0, x0, TCB_SIZE
- */
+ bl __tls_get_addr => add R0, R0, TCB_SIZE
+
+ Where R is x for lp64 mode, and w for ilp32 mode. */
if (is_local)
{
BFD_ASSERT (rel->r_offset + 4 == rel[1].r_offset);
/* No need of CALL26 relocation for tls_get_addr. */
rel[1].r_info = ELFNN_R_INFO (STN_UNDEF, R_AARCH64_NONE);
bfd_putl32 (0xd53bd040, contents + rel->r_offset + 0);
- bfd_putl32 (0x91004000, contents + rel->r_offset + 4);
+ bfd_putl32 (add_R0_R0 | (TCB_SIZE << 10),
+ contents + rel->r_offset + 4);
return bfd_reloc_ok;
}
return bfd_reloc_continue;
case BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC:
/* LD->LE relaxation (small):
- add x0, #:tlsldm_lo12:x => add x0, x0, TCB_SIZE
+ add x0, #:tlsldm_lo12:x => add R0, R0, TCB_SIZE
bl __tls_get_addr => nop
- */
+
+ Where R is x for lp64 mode, and w for ilp32 mode. */
if (is_local)
{
BFD_ASSERT (rel->r_offset + 4 == rel[1].r_offset);
BFD_ASSERT (ELFNN_R_TYPE (rel[1].r_info) == AARCH64_R (CALL26));
/* No need of CALL26 relocation for tls_get_addr. */
rel[1].r_info = ELFNN_R_INFO (STN_UNDEF, R_AARCH64_NONE);
- bfd_putl32 (0x91004000, contents + rel->r_offset + 0);
- bfd_putl32 (0xd503201f, contents + rel->r_offset + 4);
+ bfd_putl32 (add_R0_R0 | (TCB_SIZE << 10),
+ contents + rel->r_offset + 0);
+ bfd_putl32 (INSN_NOP, contents + rel->r_offset + 4);
return bfd_reloc_ok;
}
return bfd_reloc_continue;
r_symndx = ELFNN_R_SYM (rel->r_info);
r_type = ELFNN_R_TYPE (rel->r_info);
- bfd_reloc.howto = elfNN_aarch64_howto_from_type (r_type);
+ bfd_reloc.howto = elfNN_aarch64_howto_from_type (input_bfd, r_type);
howto = bfd_reloc.howto;
if (howto == NULL)
- {
- (*_bfd_error_handler)
- (_("%B: unrecognized relocation (0x%x) in section `%A'"),
- input_bfd, input_section, r_type);
- return FALSE;
- }
+ return _bfd_unrecognized_reloc (input_bfd, input_section, r_type);
+
bfd_r_type = elfNN_aarch64_bfd_reloc_from_howto (howto);
h = NULL;
if (r_type != R_AARCH64_NONE && r_type != R_AARCH64_NULL
&& 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;
- }
+ (*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);
relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
|| h->root.type == bfd_link_hash_defweak)
&& IS_AARCH64_TLS_RELOC (bfd_r_type) != (sym_type == STT_TLS))
{
- (*_bfd_error_handler)
+ _bfd_error_handler
((sym_type == STT_TLS
- ? _("%B(%A+0x%lx): %s used with TLS symbol %s")
- : _("%B(%A+0x%lx): %s used with non-TLS symbol %s")),
+ /* xgettext:c-format */
+ ? _("%pB(%pA+%#" PRIx64 "): %s used with TLS symbol %s")
+ /* xgettext:c-format */
+ : _("%pB(%pA+%#" PRIx64 "): %s used with non-TLS symbol %s")),
input_bfd,
- input_section, (long) rel->r_offset, howto->name, name);
+ input_section, (uint64_t) rel->r_offset, howto->name, name);
}
/* We relax only if we can see that there can be a valid transition
- from a reloc type to another.
- We call elfNN_aarch64_final_link_relocate unless we're completely
- done, i.e., the relaxation produced the final output we want. */
+ from a reloc type to another.
+ We call elfNN_aarch64_final_link_relocate unless we're completely
+ done, i.e., the relaxation produced the final output we want. */
relaxed_bfd_r_type = aarch64_tls_transition (input_bfd, info, r_type,
h, r_symndx);
howto = elfNN_aarch64_howto_from_bfd_reloc (bfd_r_type);
BFD_ASSERT (howto != NULL);
r_type = howto->type;
- r = elfNN_aarch64_tls_relax (globals, input_bfd, contents, rel, h);
+ r = elfNN_aarch64_tls_relax (globals, input_bfd, input_section,
+ contents, rel, h);
unresolved_reloc = 0;
}
else
r = bfd_reloc_continue;
/* There may be multiple consecutive relocations for the
- same offset. In that case we are supposed to treat the
- output of each relocation as the addend for the next. */
+ same offset. In that case we are supposed to treat the
+ output of each relocation as the addend for the next. */
if (rel + 1 < relend
&& rel->r_offset == rel[1].r_offset
&& ELFNN_R_TYPE (rel[1].r_info) != R_AARCH64_NONE
h, &unresolved_reloc,
save_addend, &addend, sym);
- switch (elfNN_aarch64_bfd_reloc_from_type (r_type))
+ switch (elfNN_aarch64_bfd_reloc_from_type (input_bfd, r_type))
{
case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC:
case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21:
indx = h && h->dynindx != -1 ? h->dynindx : 0;
need_relocs =
- (bfd_link_pic (info) || indx != 0) &&
+ (!bfd_link_executable (info) || indx != 0) &&
(h == NULL
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak);
bfd_elfNN_swap_reloca_out (output_bfd, &rela, loc);
bfd_reloc_code_real_type real_type =
- elfNN_aarch64_bfd_reloc_from_type (r_type);
+ elfNN_aarch64_bfd_reloc_from_type (input_bfd, r_type);
if (real_type == BFD_RELOC_AARCH64_TLSLD_ADR_PREL21
|| real_type == BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21
indx = h && h->dynindx != -1 ? h->dynindx : 0;
need_relocs =
- (bfd_link_pic (info) || indx != 0) &&
+ (!bfd_link_executable (info) || indx != 0) &&
(h == NULL
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak);
}
break;
- case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12:
case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21:
case BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21:
case BFD_RELOC_AARCH64_TLSDESC_LDNN_LO12_NC:
case BFD_RELOC_AARCH64_TLSDESC_LD_PREL19:
+ case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC:
+ case BFD_RELOC_AARCH64_TLSDESC_OFF_G1:
if (! symbol_tlsdesc_got_offset_mark_p (input_bfd, h, r_symndx))
{
bfd_boolean need_relocs = FALSE;
break;
}
- if (!save_addend)
- addend = 0;
-
-
/* Dynamic relocs are not propagated for SEC_DEBUGGING sections
- because such sections are not SEC_ALLOC and thus ld.so will
- not process them. */
+ because such sections are not SEC_ALLOC and thus ld.so will
+ not process them. */
if (unresolved_reloc
&& !((input_section->flags & SEC_DEBUGGING) != 0
&& 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'"),
- input_bfd, input_section, (long) rel->r_offset, howto->name,
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA+%#" PRIx64 "): "
+ "unresolvable %s relocation against symbol `%s'"),
+ input_bfd, input_section, (uint64_t) rel->r_offset, howto->name,
h->root.root.string);
return FALSE;
}
if (r != bfd_reloc_ok && r != bfd_reloc_continue)
{
bfd_reloc_code_real_type real_r_type
- = elfNN_aarch64_bfd_reloc_from_type (r_type);
+ = elfNN_aarch64_bfd_reloc_from_type (input_bfd, r_type);
switch (r)
{
case bfd_reloc_overflow:
- if (!(*info->callbacks->reloc_overflow)
- (info, (h ? &h->root : NULL), name, howto->name, (bfd_vma) 0,
- input_bfd, input_section, rel->r_offset))
- return FALSE;
+ (*info->callbacks->reloc_overflow)
+ (info, (h ? &h->root : NULL), name, howto->name, (bfd_vma) 0,
+ input_bfd, input_section, rel->r_offset);
if (real_r_type == BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15
|| real_r_type == BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14)
{
(*info->callbacks->warning)
(info,
- _("Too many GOT entries for -fpic, "
+ _("too many GOT entries for -fpic, "
"please recompile with -fPIC"),
name, input_bfd, input_section, rel->r_offset);
return FALSE;
}
+ /* Overflow can occur when a variable is referenced with a type
+ that has a larger alignment than the type with which it was
+ declared. eg:
+ file1.c: extern int foo; int a (void) { return foo; }
+ file2.c: char bar, foo, baz;
+ If the variable is placed into a data section at an offset
+ that is incompatible with the larger alignment requirement
+ overflow will occur. (Strictly speaking this is not overflow
+ but rather an alignment problem, but the bfd_reloc_ error
+ enum does not have a value to cover that situation).
+
+ Try to catch this situation here and provide a more helpful
+ error message to the user. */
+ if (addend & ((1 << howto->rightshift) - 1)
+ /* FIXME: Are we testing all of the appropriate reloc
+ types here ? */
+ && (real_r_type == BFD_RELOC_AARCH64_LD_LO19_PCREL
+ || real_r_type == BFD_RELOC_AARCH64_LDST16_LO12
+ || real_r_type == BFD_RELOC_AARCH64_LDST32_LO12
+ || real_r_type == BFD_RELOC_AARCH64_LDST64_LO12
+ || real_r_type == BFD_RELOC_AARCH64_LDST128_LO12))
+ {
+ info->callbacks->warning
+ (info, _("one possible cause of this error is that the \
+symbol is being referenced in the indicated code as if it had a larger \
+alignment than was declared where it was defined"),
+ name, input_bfd, input_section, rel->r_offset);
+ }
break;
case bfd_reloc_undefined:
- if (!((*info->callbacks->undefined_symbol)
- (info, name, input_bfd, input_section,
- rel->r_offset, TRUE)))
- return FALSE;
+ (*info->callbacks->undefined_symbol)
+ (info, name, input_bfd, input_section, rel->r_offset, TRUE);
break;
case bfd_reloc_outofrange:
common_error:
BFD_ASSERT (error_message != NULL);
- if (!((*info->callbacks->reloc_dangerous)
- (info, error_message, input_bfd, input_section,
- rel->r_offset)))
- return FALSE;
+ (*info->callbacks->reloc_dangerous)
+ (info, error_message, input_bfd, input_section, rel->r_offset);
break;
}
}
+
+ if (!save_addend)
+ addend = 0;
}
return TRUE;
object file when linking. */
static bfd_boolean
-elfNN_aarch64_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
+elfNN_aarch64_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
{
+ bfd *obfd = info->output_bfd;
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))
+ if (!_bfd_generic_verify_endian_match (ibfd, info))
return FALSE;
if (!is_aarch64_elf (ibfd) || !is_aarch64_elf (obfd))
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. */
+ 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;
fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags);
if (flags)
- fprintf (file, _("<Unrecognised flag bits set>"));
-
- fputc ('\n', file);
-
- return TRUE;
-}
-
-/* Update the got entry reference counts for the section being removed. */
-
-static bfd_boolean
-elfNN_aarch64_gc_sweep_hook (bfd *abfd,
- struct bfd_link_info *info,
- asection *sec,
- const Elf_Internal_Rela * relocs)
-{
- struct elf_aarch64_link_hash_table *htab;
- Elf_Internal_Shdr *symtab_hdr;
- struct elf_link_hash_entry **sym_hashes;
- struct elf_aarch64_local_symbol *locals;
- const Elf_Internal_Rela *rel, *relend;
-
- if (bfd_link_relocatable (info))
- return TRUE;
-
- htab = elf_aarch64_hash_table (info);
-
- if (htab == NULL)
- return FALSE;
-
- elf_section_data (sec)->local_dynrel = NULL;
-
- symtab_hdr = &elf_symtab_hdr (abfd);
- sym_hashes = elf_sym_hashes (abfd);
-
- locals = elf_aarch64_locals (abfd);
-
- relend = relocs + sec->reloc_count;
- for (rel = relocs; rel < relend; rel++)
- {
- unsigned long r_symndx;
- unsigned int r_type;
- struct elf_link_hash_entry *h = NULL;
-
- r_symndx = ELFNN_R_SYM (rel->r_info);
-
- if (r_symndx >= symtab_hdr->sh_info)
- {
-
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- while (h->root.type == bfd_link_hash_indirect
- || h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
- }
- else
- {
- Elf_Internal_Sym *isym;
-
- /* A local symbol. */
- isym = bfd_sym_from_r_symndx (&htab->sym_cache,
- abfd, r_symndx);
-
- /* Check relocation against local STT_GNU_IFUNC symbol. */
- if (isym != NULL
- && ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
- {
- h = elfNN_aarch64_get_local_sym_hash (htab, abfd, rel, FALSE);
- if (h == NULL)
- abort ();
- }
- }
-
- if (h)
- {
- struct elf_aarch64_link_hash_entry *eh;
- struct elf_dyn_relocs **pp;
- struct elf_dyn_relocs *p;
-
- eh = (struct elf_aarch64_link_hash_entry *) h;
-
- for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
- if (p->sec == sec)
- {
- /* Everything must go for SEC. */
- *pp = p->next;
- break;
- }
- }
-
- r_type = ELFNN_R_TYPE (rel->r_info);
- switch (aarch64_tls_transition (abfd,info, r_type, h ,r_symndx))
- {
- case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
- case BFD_RELOC_AARCH64_GOT_LD_PREL19:
- case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14:
- case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
- case BFD_RELOC_AARCH64_LD64_GOTOFF_LO15:
- case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15:
- case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
- case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC:
- case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1:
- case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC:
- case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21:
- case BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21:
- case BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC:
- case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC:
- case BFD_RELOC_AARCH64_TLSDESC_LD_PREL19:
- case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC:
- case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21:
- case BFD_RELOC_AARCH64_TLSGD_ADR_PREL21:
- case BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC:
- case BFD_RELOC_AARCH64_TLSGD_MOVW_G1:
- case BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
- case BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC:
- case BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
- case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19:
- case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC:
- case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1:
- case BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC:
- case BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21:
- case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21:
- if (h != NULL)
- {
- if (h->got.refcount > 0)
- h->got.refcount -= 1;
+ fprintf (file, _("<Unrecognised flag bits set>"));
- if (h->type == STT_GNU_IFUNC)
- {
- if (h->plt.refcount > 0)
- h->plt.refcount -= 1;
- }
- }
- else if (locals != NULL)
- {
- if (locals[r_symndx].got_refcount > 0)
- locals[r_symndx].got_refcount -= 1;
- }
- break;
+ fputc ('\n', file);
- case BFD_RELOC_AARCH64_CALL26:
- case BFD_RELOC_AARCH64_JUMP26:
- /* If this is a local symbol then we resolve it
- directly without creating a PLT entry. */
- if (h == NULL)
- continue;
+ return TRUE;
+}
- if (h->plt.refcount > 0)
- h->plt.refcount -= 1;
- break;
+/* Find dynamic relocs for H that apply to read-only sections. */
- case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL:
- case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
- case BFD_RELOC_AARCH64_ADR_LO21_PCREL:
- case BFD_RELOC_AARCH64_MOVW_G0_NC:
- case BFD_RELOC_AARCH64_MOVW_G1_NC:
- case BFD_RELOC_AARCH64_MOVW_G2_NC:
- case BFD_RELOC_AARCH64_MOVW_G3:
- case BFD_RELOC_AARCH64_NN:
- if (h != NULL && bfd_link_executable (info))
- {
- if (h->plt.refcount > 0)
- h->plt.refcount -= 1;
- }
- break;
+static asection *
+readonly_dynrelocs (struct elf_link_hash_entry *h)
+{
+ struct elf_dyn_relocs *p;
- default:
- break;
- }
+ for (p = elf_aarch64_hash_entry (h)->dyn_relocs; p != NULL; p = p->next)
+ {
+ asection *s = p->sec->output_section;
+
+ if (s != NULL && (s->flags & SEC_READONLY) != 0)
+ return p->sec;
}
+ return NULL;
+}
- return TRUE;
+/* Return true if we need copy relocation against EH. */
+
+static bfd_boolean
+need_copy_relocation_p (struct elf_aarch64_link_hash_entry *eh)
+{
+ struct elf_dyn_relocs *p;
+ asection *s;
+
+ for (p = eh->dyn_relocs; p != NULL; p = p->next)
+ {
+ /* If there is any pc-relative reference, we need to keep copy relocation
+ to avoid propagating the relocation into runtime that current glibc
+ does not support. */
+ if (p->pc_count)
+ return TRUE;
+
+ s = p->sec->output_section;
+ /* Need copy relocation if it's against read-only section. */
+ if (s != NULL && (s->flags & SEC_READONLY) != 0)
+ return TRUE;
+ }
+
+ return FALSE;
}
/* Adjust a symbol defined by a dynamic object and referenced by a
struct elf_link_hash_entry *h)
{
struct elf_aarch64_link_hash_table *htab;
- asection *s;
+ asection *s, *srel;
/* If this is a function, put it in the procedure linkage table. We
will fill in the contents of the procedure linkage table later,
/* If this is a weak symbol, and there is a real definition, the
processor independent code will have arranged for us to see the
real definition first, and we can just use the same value. */
- if (h->u.weakdef != NULL)
+ if (h->is_weakalias)
{
- BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
- || h->u.weakdef->root.type == bfd_link_hash_defweak);
- h->root.u.def.section = h->u.weakdef->root.u.def.section;
- h->root.u.def.value = h->u.weakdef->root.u.def.value;
+ struct elf_link_hash_entry *def = weakdef (h);
+ BFD_ASSERT (def->root.type == bfd_link_hash_defined);
+ h->root.u.def.section = def->root.u.def.section;
+ h->root.u.def.value = def->root.u.def.value;
if (ELIMINATE_COPY_RELOCS || info->nocopyreloc)
- h->non_got_ref = h->u.weakdef->non_got_ref;
+ h->non_got_ref = def->non_got_ref;
return TRUE;
}
return TRUE;
}
+ if (ELIMINATE_COPY_RELOCS)
+ {
+ struct elf_aarch64_link_hash_entry *eh;
+ /* If we don't find any dynamic relocs in read-only sections, then
+ we'll be keeping the dynamic relocs and avoiding the copy reloc. */
+ eh = (struct elf_aarch64_link_hash_entry *) h;
+ if (!need_copy_relocation_p (eh))
+ {
+ h->non_got_ref = 0;
+ return TRUE;
+ }
+ }
+
/* We must allocate the symbol in our .dynbss section, which will
become part of the .bss section of the executable. There will be
an entry for this symbol in the .dynsym section. The dynamic
/* We must generate a R_AARCH64_COPY reloc to tell the dynamic linker
to copy the initial value out of the dynamic object and into the
runtime process image. */
+ if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
+ {
+ s = htab->root.sdynrelro;
+ srel = htab->root.sreldynrelro;
+ }
+ else
+ {
+ s = htab->root.sdynbss;
+ srel = htab->root.srelbss;
+ }
if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
{
- htab->srelbss->size += RELOC_SIZE (htab);
+ srel->size += RELOC_SIZE (htab);
h->needs_copy = 1;
}
- s = htab->sdynbss;
-
return _bfd_elf_adjust_dynamic_copy (info, h, s);
}
struct elf_link_hash_table *htab = elf_hash_table (info);
/* This function may be called more than once. */
- s = bfd_get_linker_section (abfd, ".got");
- if (s != NULL)
+ if (htab->sgot != NULL)
return TRUE;
flags = bed->dynamic_sec_flags;
for (rel = relocs; rel < rel_end; rel++)
{
struct elf_link_hash_entry *h;
- unsigned long r_symndx;
+ unsigned int r_symndx;
unsigned int r_type;
bfd_reloc_code_real_type bfd_r_type;
Elf_Internal_Sym *isym;
if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
{
- (*_bfd_error_handler) (_("%B: bad symbol index: %d"), abfd,
- r_symndx);
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: bad symbol index: %d"), abfd, r_symndx);
return FALSE;
}
while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
- /* PR15323, ref flags aren't set for references in the same
- object. */
- h->root.non_ir_ref = 1;
}
/* Could be done earlier, if h were already available. */
if (h != NULL)
{
+ /* If a relocation refers to _GLOBAL_OFFSET_TABLE_, create the .got.
+ This shows up in particular in an R_AARCH64_PREL64 in large model
+ when calculating the pc-relative address to .got section which is
+ used to initialize the gp register. */
+ if (h->root.root.string
+ && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+ {
+ if (htab->root.dynobj == NULL)
+ htab->root.dynobj = abfd;
+
+ if (! aarch64_elf_create_got_section (htab->root.dynobj, info))
+ return FALSE;
+
+ BFD_ASSERT (h == htab->root.hgot);
+ }
+
/* Create the ifunc sections for static executables. If we
never see an indirect function symbol nor we are building
a static executable, those sections will be empty and
break;
}
- /* It is referenced by a non-shared object. */
+ /* It is referenced by a non-shared object. */
h->ref_regular = 1;
- h->root.non_ir_ref = 1;
}
switch (bfd_r_type)
{
+ case BFD_RELOC_AARCH64_16:
+#if ARCH_SIZE == 64
+ case BFD_RELOC_AARCH64_32:
+#endif
+ if (bfd_link_pic (info) && (sec->flags & SEC_ALLOC) != 0)
+ {
+ if (h != NULL
+ /* This is an absolute symbol. It represents a value instead
+ of an address. */
+ && (bfd_is_abs_symbol (&h->root)
+ /* This is an undefined symbol. */
+ || h->root.type == bfd_link_hash_undefined))
+ break;
+
+ /* For local symbols, defined global symbols in a non-ABS section,
+ it is assumed that the value is an address. */
+ int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START;
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: relocation %s against `%s' can not be used when making "
+ "a shared object"),
+ abfd, elfNN_aarch64_howto_table[howto_index].name,
+ (h) ? h->root.root.string : "a local symbol");
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ else
+ break;
+
+ case BFD_RELOC_AARCH64_MOVW_G0_NC:
+ case BFD_RELOC_AARCH64_MOVW_G1_NC:
+ case BFD_RELOC_AARCH64_MOVW_G2_NC:
+ case BFD_RELOC_AARCH64_MOVW_G3:
+ if (bfd_link_pic (info))
+ {
+ int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START;
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: relocation %s against `%s' can not be used when making "
+ "a shared object; recompile with -fPIC"),
+ abfd, elfNN_aarch64_howto_table[howto_index].name,
+ (h) ? h->root.root.string : "a local symbol");
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ /* Fall through. */
+
+ case BFD_RELOC_AARCH64_16_PCREL:
+ case BFD_RELOC_AARCH64_32_PCREL:
+ case BFD_RELOC_AARCH64_64_PCREL:
+ case BFD_RELOC_AARCH64_ADD_LO12:
+ case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL:
+ case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
+ case BFD_RELOC_AARCH64_ADR_LO21_PCREL:
+ case BFD_RELOC_AARCH64_LDST128_LO12:
+ case BFD_RELOC_AARCH64_LDST16_LO12:
+ case BFD_RELOC_AARCH64_LDST32_LO12:
+ case BFD_RELOC_AARCH64_LDST64_LO12:
+ case BFD_RELOC_AARCH64_LDST8_LO12:
+ case BFD_RELOC_AARCH64_LD_LO19_PCREL:
+ if (h == NULL || bfd_link_pic (info))
+ break;
+ /* Fall through. */
+
case BFD_RELOC_AARCH64_NN:
/* We don't need to handle relocs into sections not going into
/* No need to do anything if we're not creating a shared
object. */
- if (! bfd_link_pic (info))
+ if (!(bfd_link_pic (info)
+ /* If on the other hand, we are creating an executable, we
+ may need to keep relocations for symbols satisfied by a
+ dynamic library if we manage to avoid copy relocs for the
+ symbol.
+
+ NOTE: Currently, there is no support of copy relocs
+ elimination on pc-relative relocation types, because there is
+ no dynamic relocation support for them in glibc. We still
+ record the dynamic symbol reference for them. This is
+ because one symbol may be referenced by both absolute
+ relocation (for example, BFD_RELOC_AARCH64_NN) and
+ pc-relative relocation. We need full symbol reference
+ information to make correct decision later in
+ elfNN_aarch64_adjust_dynamic_symbol. */
+ || (ELIMINATE_COPY_RELOCS
+ && !bfd_link_pic (info)
+ && h != NULL
+ && (h->root.type == bfd_link_hash_defweak
+ || !h->def_regular))))
break;
{
struct elf_dyn_relocs *p;
struct elf_dyn_relocs **head;
+ int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START;
/* We must copy these reloc types into the output file.
Create a reloc section in dynobj and make room for
p->count += 1;
+ if (elfNN_aarch64_howto_table[howto_index].pc_relative)
+ p->pc_count += 1;
}
break;
case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC:
case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1:
- case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12:
case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21:
case BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21:
case BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC:
- case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12:
case BFD_RELOC_AARCH64_TLSDESC_LD_PREL19:
+ case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC:
+ case BFD_RELOC_AARCH64_TLSDESC_OFF_G1:
case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC:
case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21:
case BFD_RELOC_AARCH64_TLSGD_ADR_PREL21:
break;
}
- case BFD_RELOC_AARCH64_MOVW_G0_NC:
- case BFD_RELOC_AARCH64_MOVW_G1_NC:
- case BFD_RELOC_AARCH64_MOVW_G2_NC:
- case BFD_RELOC_AARCH64_MOVW_G3:
- if (bfd_link_pic (info))
- {
- int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START;
- (*_bfd_error_handler)
- (_("%B: relocation %s against `%s' can not be used when making "
- "a shared object; recompile with -fPIC"),
- abfd, elfNN_aarch64_howto_table[howto_index].name,
- (h) ? h->root.root.string : "a local symbol");
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
- }
-
- case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL:
- case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
- case BFD_RELOC_AARCH64_ADR_LO21_PCREL:
- if (h != NULL && bfd_link_executable (info))
- {
- /* If this reloc is in a read-only section, we might
- need a copy reloc. We can't check reliably at this
- stage whether the section is read-only, as input
- sections have not yet been mapped to output sections.
- Tentatively set the flag for now, and correct in
- adjust_dynamic_symbol. */
- h->non_got_ref = 1;
- h->plt.refcount += 1;
- h->pointer_equality_needed = 1;
- }
- /* FIXME:: RR need to handle these in shared libraries
- and essentially bomb out as these being non-PIC
- relocations in shared libraries. */
- break;
-
case BFD_RELOC_AARCH64_CALL26:
case BFD_RELOC_AARCH64_JUMP26:
/* If this is a local symbol then we resolve it
const asection *rel_sec ATTRIBUTE_UNUSED,
const Elf_Internal_Rela *rela)
{
+ struct elf_aarch64_link_hash_table *htab = elf_aarch64_hash_table (info);
+
+ if (htab->root.dynsym != NULL
+ && htab->root.dynsym->contents != NULL)
+ {
+ /* Check relocation against STT_GNU_IFUNC symbol if there are
+ dynamic symbols. */
+ bfd *abfd = info->output_bfd;
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ unsigned long r_symndx = ELFNN_R_SYM (rela->r_info);
+ if (r_symndx != STN_UNDEF)
+ {
+ Elf_Internal_Sym sym;
+ if (!bed->s->swap_symbol_in (abfd,
+ (htab->root.dynsym->contents
+ + r_symndx * bed->s->sizeof_sym),
+ 0, &sym))
+ {
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB symbol number %lu references"
+ " nonexistent SHT_SYMTAB_SHNDX section"),
+ abfd, r_symndx);
+ /* Ideally an error class should be returned here. */
+ }
+ else if (ELF_ST_TYPE (sym.st_info) == STT_GNU_IFUNC)
+ return reloc_class_ifunc;
+ }
+ }
+
switch ((int) ELFNN_R_TYPE (rela->r_info))
{
+ case AARCH64_R (IRELATIVE):
+ return reloc_class_ifunc;
case AARCH64_R (RELATIVE):
return reloc_class_relative;
case AARCH64_R (JUMP_SLOT):
if (!elfNN_aarch64_output_map_sym (osi, AARCH64_MAP_INSN, addr))
return FALSE;
break;
+ case aarch64_stub_none:
+ break;
default:
abort ();
elfNN_aarch64_create_dynamic_sections (bfd *dynobj,
struct bfd_link_info *info)
{
- struct elf_aarch64_link_hash_table *htab;
-
/* We need to create .got section. */
if (!aarch64_elf_create_got_section (dynobj, info))
return FALSE;
- if (!_bfd_elf_create_dynamic_sections (dynobj, info))
- return FALSE;
-
- htab = elf_aarch64_hash_table (info);
- htab->sdynbss = bfd_get_linker_section (dynobj, ".dynbss");
- if (!bfd_link_pic (info))
- htab->srelbss = bfd_get_linker_section (dynobj, ".rela.bss");
-
- if (!htab->sdynbss || (!bfd_link_pic (info) && !htab->srelbss))
- abort ();
-
- return TRUE;
+ return _bfd_elf_create_dynamic_sections (dynobj, info);
}
because we will also be presented with the concrete instance of
the symbol and elfNN_aarch64_copy_indirect_symbol () will have been
called to copy all relevant data from the generic to the concrete
- symbol instance.
- */
+ symbol instance. */
if (h->root.type == bfd_link_hash_indirect)
return TRUE;
else if (htab->root.dynamic_sections_created && h->plt.refcount > 0)
{
/* Make sure this symbol is output as a dynamic symbol.
- Undefined weak syms won't yet be marked as dynamic. */
- if (h->dynindx == -1 && !h->forced_local)
+ Undefined weak syms won't yet be marked as dynamic. */
+ if (h->dynindx == -1 && !h->forced_local
+ && h->root.type == bfd_link_hash_undefweak)
{
if (!bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
/* Make room for this entry. For now we only create the
small model PLT entries. We later need to find a way
of relaxing into these from the large model PLT entries. */
- s->size += PLT_SMALL_ENTRY_SIZE;
+ s->size += htab->plt_entry_size;
/* We also need to make an entry in the .got.plt section, which
will be placed in the .got section by the linker script. */
dyn = htab->root.dynamic_sections_created;
/* Make sure this symbol is output as a dynamic symbol.
- Undefined weak syms won't yet be marked as dynamic. */
- if (dyn && h->dynindx == -1 && !h->forced_local)
+ Undefined weak syms won't yet be marked as dynamic. */
+ if (dyn && h->dynindx == -1 && !h->forced_local
+ && h->root.type == bfd_link_hash_undefweak)
{
if (!bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak)
&& (bfd_link_pic (info)
- || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
+ || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
+ /* Undefined weak symbol in static PIE resolves to 0 without
+ any dynamic relocations. */
+ && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
{
htab->root.srelgot->size += RELOC_SIZE (htab);
}
indx = h && h->dynindx != -1 ? h->dynindx : 0;
if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak)
- && (bfd_link_pic (info)
+ && (!bfd_link_executable (info)
|| indx != 0
|| WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
{
if (bfd_link_pic (info))
{
/* Relocs that use pc_count are those that appear on a call
- insn, or certain REL relocs that can generated via assembly.
- We want calls to protected symbols to resolve directly to the
- function rather than going via the plt. If people want
- function pointer comparisons to work as expected then they
- should avoid writing weird assembly. */
+ insn, or certain REL relocs that can generated via assembly.
+ We want calls to protected symbols to resolve directly to the
+ function rather than going via the plt. If people want
+ function pointer comparisons to work as expected then they
+ should avoid writing weird assembly. */
if (SYMBOL_CALLS_LOCAL (info, h))
{
struct elf_dyn_relocs **pp;
}
/* Also discard relocs on undefined weak syms with non-default
- visibility. */
+ visibility. */
if (eh->dyn_relocs != NULL && h->root.type == bfd_link_hash_undefweak)
{
- if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+ if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+ || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
eh->dyn_relocs = NULL;
/* Make sure undefined weak symbols are output as a dynamic
symbol in PIEs. */
else if (h->dynindx == -1
&& !h->forced_local
+ && h->root.type == bfd_link_hash_undefweak
&& !bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
}
else if (ELIMINATE_COPY_RELOCS)
{
/* For the non-shared case, discard space for relocs against
- symbols which turn out to need copy relocs or are not
- dynamic. */
+ symbols which turn out to need copy relocs or are not
+ dynamic. */
if (!h->non_got_ref
&& ((h->def_dynamic
Undefined weak syms won't yet be marked as dynamic. */
if (h->dynindx == -1
&& !h->forced_local
+ && h->root.type == bfd_link_hash_undefweak
&& !bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
because we will also be presented with the concrete instance of
the symbol and elfNN_aarch64_copy_indirect_symbol () will have been
called to copy all relevant data from the generic to the concrete
- symbol instance.
- */
+ symbol instance. */
if (h->root.type == bfd_link_hash_indirect)
return TRUE;
&& h->def_regular)
return _bfd_elf_allocate_ifunc_dyn_relocs (info, h,
&eh->dyn_relocs,
+ NULL,
htab->plt_entry_size,
htab->plt_header_size,
- GOT_ENTRY_SIZE);
+ GOT_ENTRY_SIZE,
+ FALSE);
return TRUE;
}
return elfNN_aarch64_allocate_ifunc_dynrelocs (h, inf);
}
-/* Find any dynamic relocs that apply to read-only sections. */
+/* Set DF_TEXTREL if we find any dynamic relocs that apply to
+ read-only sections. */
static bfd_boolean
-aarch64_readonly_dynrelocs (struct elf_link_hash_entry * h, void * inf)
+maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p)
{
- struct elf_aarch64_link_hash_entry * eh;
- struct elf_dyn_relocs * p;
+ asection *sec;
- eh = (struct elf_aarch64_link_hash_entry *) h;
- for (p = eh->dyn_relocs; p != NULL; p = p->next)
- {
- asection *s = p->sec;
+ if (h->root.type == bfd_link_hash_indirect)
+ return TRUE;
- if (s != NULL && (s->flags & SEC_READONLY) != 0)
- {
- struct bfd_link_info *info = (struct bfd_link_info *) inf;
+ sec = readonly_dynrelocs (h);
+ if (sec != NULL)
+ {
+ struct bfd_link_info *info = (struct bfd_link_info *) info_p;
- info->flags |= DF_TEXTREL;
+ info->flags |= DF_TEXTREL;
+ info->callbacks->minfo
+ (_("%pB: dynamic relocation against `%pT' in read-only section `%pA'\n"),
+ sec->owner, h->root.root.string, sec);
- /* Not an error, just cut short the traversal. */
- return FALSE;
- }
+ /* Not an error, just cut short the traversal. */
+ return FALSE;
}
return TRUE;
}
/* This is the most important function of all . Innocuosly named
though ! */
+
static bfd_boolean
elfNN_aarch64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
struct bfd_link_info *info)
if (htab->tlsdesc_plt)
{
if (htab->root.splt->size == 0)
- htab->root.splt->size += PLT_ENTRY_SIZE;
+ htab->root.splt->size += htab->plt_header_size;
htab->tlsdesc_plt = htab->root.splt->size;
- htab->root.splt->size += PLT_TLSDESC_ENTRY_SIZE;
+ htab->root.splt->size += htab->tlsdesc_plt_entry_size;
/* If we're not using lazy TLS relocations, don't generate the
- GOT entry required. */
+ GOT entry required. */
if (!(info->flags & DF_BIND_NOW))
{
htab->dt_tlsdesc_got = htab->root.sgot->size;
|| s == htab->root.sgot
|| s == htab->root.sgotplt
|| s == htab->root.iplt
- || s == htab->root.igotplt || s == htab->sdynbss)
+ || s == htab->root.igotplt
+ || s == htab->root.sdynbss
+ || s == htab->root.sdynrelro)
{
/* Strip this section if we don't need it; see the
comment below. */
adjust_dynamic_symbol is called, and it is that
function which decides whether anything needs to go
into these sections. */
-
s->flags |= SEC_EXCLUDE;
continue;
}
continue;
/* Allocate memory for the section contents. We use bfd_zalloc
- here in case unused entries are not reclaimed before the
- section's contents are written out. This should not happen,
- but this way if it does, we get a R_AARCH64_NONE reloc instead
- of garbage. */
+ here in case unused entries are not reclaimed before the
+ section's contents are written out. This should not happen,
+ but this way if it does, we get a R_AARCH64_NONE reloc instead
+ of garbage. */
s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size);
if (s->contents == NULL)
return FALSE;
if (htab->root.dynamic_sections_created)
{
/* Add some entries to the .dynamic section. We fill in the
- values later, in elfNN_aarch64_finish_dynamic_sections, but we
- must add the entries now so that we get the correct size for
- the .dynamic section. The DT_DEBUG entry is filled in by the
- dynamic linker and used by the debugger. */
+ values later, in elfNN_aarch64_finish_dynamic_sections, but we
+ must add the entries now so that we get the correct size for
+ the .dynamic section. The DT_DEBUG entry is filled in by the
+ dynamic linker and used by the debugger. */
#define add_dynamic_entry(TAG, VAL) \
_bfd_elf_add_dynamic_entry (info, TAG, VAL)
&& (!add_dynamic_entry (DT_TLSDESC_PLT, 0)
|| !add_dynamic_entry (DT_TLSDESC_GOT, 0)))
return FALSE;
+
+ if ((elf_aarch64_tdata (output_bfd)->plt_type == PLT_BTI_PAC)
+ && (!add_dynamic_entry (DT_AARCH64_BTI_PLT, 0)
+ || !add_dynamic_entry (DT_AARCH64_PAC_PLT, 0)))
+ return FALSE;
+
+ else if ((elf_aarch64_tdata (output_bfd)->plt_type == PLT_BTI)
+ && !add_dynamic_entry (DT_AARCH64_BTI_PLT, 0))
+ return FALSE;
+
+ else if ((elf_aarch64_tdata (output_bfd)->plt_type == PLT_PAC)
+ && !add_dynamic_entry (DT_AARCH64_PAC_PLT, 0))
+ return FALSE;
}
if (relocs)
/* 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, aarch64_readonly_dynrelocs,
- info);
+ elf_link_hash_traverse (&htab->root, maybe_set_textrel, info);
if ((info->flags & DF_TEXTREL) != 0)
{
{
reloc_howto_type *howto = elfNN_aarch64_howto_from_bfd_reloc (r_type);
- _bfd_aarch64_elf_put_addend (output_bfd, plt_entry, r_type, howto, value);
+ /* FIXME: We should check the return value from this function call. */
+ (void) _bfd_aarch64_elf_put_addend (output_bfd, plt_entry, r_type, howto, value);
}
static void
gotplt->output_offset + got_offset;
/* Copy in the boiler-plate for the PLTn entry. */
- memcpy (plt_entry, elfNN_aarch64_small_plt_entry, PLT_SMALL_ENTRY_SIZE);
+ memcpy (plt_entry, htab->plt_entry, htab->plt_entry_size);
+
+ /* First instruction in BTI enabled PLT stub is a BTI
+ instruction so skip it. */
+ if (elf_aarch64_tdata (output_bfd)->plt_type & PLT_BTI
+ && elf_elfheader (output_bfd)->e_type == ET_EXEC)
+ plt_entry = plt_entry + 4;
/* Fill in the top 21 bits for this: ADRP x16, PLT_GOT + n * 8.
ADRP: ((PG(S+A)-PG(P)) >> 12) & 0x1fffff */
/* Finish up dynamic symbol handling. We set the contents of various
dynamic sections here. */
+
static bfd_boolean
elfNN_aarch64_finish_dynamic_symbol (bfd *output_bfd,
struct bfd_link_info *info,
asection *plt, *gotplt, *relplt;
/* This symbol has an entry in the procedure linkage table. Set
- it up. */
+ it up. */
/* When building a static executable, use .iplt, .igot.plt and
.rela.iplt sections for STT_GNU_IFUNC symbols. */
|| plt == NULL
|| gotplt == NULL
|| relplt == NULL)
- abort ();
+ return FALSE;
elfNN_aarch64_create_small_pltn_entry (h, htab, output_bfd, info);
if (!h->def_regular)
}
if (h->got.offset != (bfd_vma) - 1
- && elf_aarch64_hash_entry (h)->got_type == GOT_NORMAL)
+ && elf_aarch64_hash_entry (h)->got_type == GOT_NORMAL
+ /* Undefined weak symbol in static PIE resolves to 0 without
+ any dynamic relocations. */
+ && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
{
Elf_Internal_Rela rela;
bfd_byte *loc;
/* This symbol has an entry in the global offset table. Set it
- up. */
+ up. */
if (htab->root.sgot == NULL || htab->root.srelgot == NULL)
abort ();
}
else if (bfd_link_pic (info) && SYMBOL_REFERENCES_LOCAL (info, h))
{
- if (!h->def_regular)
+ if (!(h->def_regular || ELF_COMMON_DEF_P (h)))
return FALSE;
BFD_ASSERT ((h->got.offset & 1) != 0);
if (h->needs_copy)
{
Elf_Internal_Rela rela;
+ asection *s;
bfd_byte *loc;
/* This symbol needs a copy reloc. Set it up. */
-
if (h->dynindx == -1
|| (h->root.type != bfd_link_hash_defined
&& h->root.type != bfd_link_hash_defweak)
- || htab->srelbss == NULL)
+ || htab->root.srelbss == NULL)
abort ();
rela.r_offset = (h->root.u.def.value
+ h->root.u.def.section->output_offset);
rela.r_info = ELFNN_R_INFO (h->dynindx, AARCH64_R (COPY));
rela.r_addend = 0;
- loc = htab->srelbss->contents;
- loc += htab->srelbss->reloc_count++ * RELOC_SIZE (htab);
+ if (h->root.u.def.section == htab->root.sdynrelro)
+ s = htab->root.sreldynrelro;
+ else
+ s = htab->root.srelbss;
+ loc = s->contents + s->reloc_count++ * RELOC_SIZE (htab);
bfd_elfNN_swap_reloca_out (output_bfd, &rela, loc);
}
// GOTPLT entry for this.
br x17
PLT0 will be slightly different in ELF32 due to different got entry
- size.
- */
+ size. */
bfd_vma plt_got_2nd_ent; /* Address of GOT[2]. */
bfd_vma plt_base;
- memcpy (htab->root.splt->contents, elfNN_aarch64_small_plt0_entry,
- PLT_ENTRY_SIZE);
+ memcpy (htab->root.splt->contents, htab->plt0_entry,
+ htab->plt_header_size);
elf_section_data (htab->root.splt->output_section)->this_hdr.sh_entsize =
- PLT_ENTRY_SIZE;
+ htab->plt_header_size;
plt_got_2nd_ent = (htab->root.sgotplt->output_section->vma
+ htab->root.sgotplt->output_offset
plt_base = htab->root.splt->output_section->vma +
htab->root.splt->output_offset;
+ /* First instruction in BTI enabled PLT stub is a BTI
+ instruction so skip it. */
+ bfd_byte *plt0_entry = htab->root.splt->contents;
+ if (elf_aarch64_tdata (output_bfd)->plt_type & PLT_BTI)
+ plt0_entry = plt0_entry + 4;
+
/* Fill in the top 21 bits for this: ADRP x16, PLT_GOT + n * 8.
ADRP: ((PG(S+A)-PG(P)) >> 12) & 0x1fffff */
elf_aarch64_update_plt_entry (output_bfd, BFD_RELOC_AARCH64_ADR_HI21_PCREL,
- htab->root.splt->contents + 4,
+ plt0_entry + 4,
PG (plt_got_2nd_ent) - PG (plt_base + 4));
elf_aarch64_update_plt_entry (output_bfd, BFD_RELOC_AARCH64_LDSTNN_LO12,
- htab->root.splt->contents + 8,
+ plt0_entry + 8,
PG_OFFSET (plt_got_2nd_ent));
elf_aarch64_update_plt_entry (output_bfd, BFD_RELOC_AARCH64_ADD_LO12,
- htab->root.splt->contents + 12,
+ plt0_entry + 12,
PG_OFFSET (plt_got_2nd_ent));
}
break;
case DT_JMPREL:
- dyn.d_un.d_ptr = htab->root.srelplt->output_section->vma;
+ s = htab->root.srelplt;
+ dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
break;
case DT_PLTRELSZ:
dyn.d_un.d_val = s->size;
break;
- case DT_RELASZ:
- /* The procedure linkage table relocs (DT_JMPREL) should
- not be included in the overall relocs (DT_RELA).
- Therefore, we override the DT_RELASZ entry here to
- make it not include the JMPREL relocs. Since the
- linker script arranges for .rela.plt to follow all
- other relocation sections, we don't have to worry
- about changing the DT_RELA entry. */
- if (htab->root.srelplt != NULL)
- {
- s = htab->root.srelplt;
- dyn.d_un.d_val -= s->size;
- }
- break;
-
case DT_TLSDESC_PLT:
s = htab->root.splt;
dyn.d_un.d_ptr = s->output_section->vma + s->output_offset
bfd_put_NN (output_bfd, (bfd_vma) 0,
htab->root.sgot->contents + htab->dt_tlsdesc_got);
+ const bfd_byte *entry = elfNN_aarch64_tlsdesc_small_plt_entry;
+ htab->tlsdesc_plt_entry_size = PLT_TLSDESC_ENTRY_SIZE;
+
+ aarch64_plt_type type = elf_aarch64_tdata (output_bfd)->plt_type;
+ if (type == PLT_BTI || type == PLT_BTI_PAC)
+ {
+ entry = elfNN_aarch64_tlsdesc_small_plt_bti_entry;
+ htab->tlsdesc_plt_entry_size = PLT_BTI_TLSDESC_ENTRY_SIZE;
+ }
+
memcpy (htab->root.splt->contents + htab->tlsdesc_plt,
- elfNN_aarch64_tlsdesc_small_plt_entry,
- sizeof (elfNN_aarch64_tlsdesc_small_plt_entry));
+ entry, htab->tlsdesc_plt_entry_size);
{
bfd_vma adrp1_addr =
bfd_byte *plt_entry =
htab->root.splt->contents + htab->tlsdesc_plt;
+ /* First instruction in BTI enabled PLT stub is a BTI
+ instruction so skip it. */
+ if (type & PLT_BTI)
+ {
+ plt_entry = plt_entry + 4;
+ adrp1_addr = adrp1_addr + 4;
+ adrp2_addr = adrp2_addr + 4;
+ }
+
/* adrp x2, DT_TLSDESC_GOT */
elf_aarch64_update_plt_entry (output_bfd,
BFD_RELOC_AARCH64_ADR_HI21_PCREL,
{
if (bfd_is_abs_section (htab->root.sgotplt->output_section))
{
- (*_bfd_error_handler)
- (_("discarded output section: `%A'"), htab->root.sgotplt);
+ _bfd_error_handler
+ (_("discarded output section: `%pA'"), htab->root.sgotplt);
return FALSE;
}
return TRUE;
}
+/* Check if BTI enabled PLTs are needed. Returns the type needed. */
+static aarch64_plt_type
+get_plt_type (bfd *abfd)
+{
+ aarch64_plt_type ret = PLT_NORMAL;
+ bfd_byte *contents, *extdyn, *extdynend;
+ asection *sec = bfd_get_section_by_name (abfd, ".dynamic");
+ if (!sec || !bfd_malloc_and_get_section (abfd, sec, &contents))
+ return ret;
+ extdyn = contents;
+ extdynend = contents + sec->size;
+ for (; extdyn < extdynend; extdyn += sizeof (ElfNN_External_Dyn))
+ {
+ Elf_Internal_Dyn dyn;
+ bfd_elfNN_swap_dyn_in (abfd, extdyn, &dyn);
+
+ /* Let's check the processor specific dynamic array tags. */
+ bfd_vma tag = dyn.d_tag;
+ if (tag < DT_LOPROC || tag > DT_HIPROC)
+ continue;
+
+ switch (tag)
+ {
+ case DT_AARCH64_BTI_PLT:
+ ret |= PLT_BTI;
+ break;
+
+ case DT_AARCH64_PAC_PLT:
+ ret |= PLT_PAC;
+ break;
+
+ default: break;
+ }
+ }
+ free (contents);
+ return ret;
+}
+
+static long
+elfNN_aarch64_get_synthetic_symtab (bfd *abfd,
+ long symcount,
+ asymbol **syms,
+ long dynsymcount,
+ asymbol **dynsyms,
+ asymbol **ret)
+{
+ elf_aarch64_tdata (abfd)->plt_type = get_plt_type (abfd);
+ return _bfd_elf_get_synthetic_symtab (abfd, symcount, syms,
+ dynsymcount, dynsyms, ret);
+}
+
/* Return address for Ith PLT stub in section PLT, for relocation REL
or (bfd_vma) -1 if it should not be included. */
elfNN_aarch64_plt_sym_val (bfd_vma i, const asection *plt,
const arelent *rel ATTRIBUTE_UNUSED)
{
- return plt->vma + PLT_ENTRY_SIZE + i * PLT_SMALL_ENTRY_SIZE;
+ size_t plt0_size = PLT_ENTRY_SIZE;
+ size_t pltn_size = PLT_SMALL_ENTRY_SIZE;
+
+ if (elf_aarch64_tdata (plt->owner)->plt_type == PLT_BTI_PAC)
+ {
+ plt0_size = PLT_BTI_PAC_ENTRY_SIZE;
+ if (elf_elfheader (plt->owner)->e_type == ET_EXEC)
+ pltn_size = PLT_BTI_PAC_SMALL_ENTRY_SIZE;
+ else
+ pltn_size = PLT_PAC_SMALL_ENTRY_SIZE;
+ }
+ else if (elf_aarch64_tdata (plt->owner)->plt_type == PLT_BTI)
+ {
+ plt0_size = PLT_BTI_ENTRY_SIZE;
+ if (elf_elfheader (plt->owner)->e_type == ET_EXEC)
+ pltn_size = PLT_BTI_SMALL_ENTRY_SIZE;
+ }
+ else if (elf_aarch64_tdata (plt->owner)->plt_type == PLT_PAC)
+ {
+ plt0_size = PLT_PAC_ENTRY_SIZE;
+ pltn_size = PLT_PAC_SMALL_ENTRY_SIZE;
+ }
+
+ return plt->vma + plt0_size + i * pltn_size;
+}
+
+/* Returns TRUE if NAME is an AArch64 mapping symbol.
+ The ARM ELF standard defines $x (for A64 code) and $d (for data).
+ It also allows a period initiated suffix to be added to the symbol, ie:
+ "$[adtx]\.[:sym_char]+". */
+
+static bfd_boolean
+is_aarch64_mapping_symbol (const char * name)
+{
+ return name != NULL /* Paranoia. */
+ && name[0] == '$' /* Note: if objcopy --prefix-symbols has been used then
+ the mapping symbols could have acquired a prefix.
+ We do not support this here, since such symbols no
+ longer conform to the ARM ELF ABI. */
+ && (name[1] == 'd' || name[1] == 'x')
+ && (name[2] == 0 || name[2] == '.');
+ /* FIXME: Strictly speaking the symbol is only a valid mapping symbol if
+ any characters that follow the period are legal characters for the body
+ of a symbol's name. For now we just assume that this is the case. */
+}
+
+/* Make sure that mapping symbols in object files are not removed via the
+ "strip --strip-unneeded" tool. These symbols might needed in order to
+ correctly generate linked files. Once an object file has been linked,
+ it should be safe to remove them. */
+
+static void
+elfNN_aarch64_backend_symbol_processing (bfd *abfd, asymbol *sym)
+{
+ if (((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
+ && sym->section != bfd_abs_section_ptr
+ && is_aarch64_mapping_symbol (sym->name))
+ sym->flags |= BSF_KEEP;
+}
+
+/* Implement elf_backend_setup_gnu_properties for AArch64. It serves as a
+ wrapper function for _bfd_aarch64_elf_link_setup_gnu_properties to account
+ for the effect of GNU properties of the output_bfd. */
+static bfd *
+elfNN_aarch64_link_setup_gnu_properties (struct bfd_link_info *info)
+{
+ uint32_t prop = elf_aarch64_tdata (info->output_bfd)->gnu_and_prop;
+ bfd *pbfd = _bfd_aarch64_elf_link_setup_gnu_properties (info, &prop);
+ elf_aarch64_tdata (info->output_bfd)->gnu_and_prop = prop;
+ elf_aarch64_tdata (info->output_bfd)->plt_type
+ |= (prop & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) ? PLT_BTI : 0;
+ setup_plt_values (info, elf_aarch64_tdata (info->output_bfd)->plt_type);
+ return pbfd;
}
+/* Implement elf_backend_merge_gnu_properties for AArch64. It serves as a
+ wrapper function for _bfd_aarch64_elf_merge_gnu_properties to account
+ for the effect of GNU properties of the output_bfd. */
+static bfd_boolean
+elfNN_aarch64_merge_gnu_properties (struct bfd_link_info *info,
+ bfd *abfd, bfd *bbfd,
+ elf_property *aprop,
+ elf_property *bprop)
+{
+ uint32_t prop
+ = elf_aarch64_tdata (info->output_bfd)->gnu_and_prop;
+
+ /* If output has been marked with BTI using command line argument, give out
+ warning if necessary. */
+ /* Properties are merged per type, hence only check for warnings when merging
+ GNU_PROPERTY_AARCH64_FEATURE_1_AND. */
+ if (((aprop && aprop->pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND)
+ || (bprop && bprop->pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND))
+ && (prop & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)
+ && (!elf_aarch64_tdata (info->output_bfd)->no_bti_warn))
+ {
+ if ((aprop && !(aprop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_BTI))
+ || !aprop)
+ {
+ _bfd_error_handler (_("%pB: warning: BTI turned on by --force-bti when "
+ "all inputs do not have BTI in NOTE section."),
+ abfd);
+ }
+ if ((bprop && !(bprop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_BTI))
+ || !bprop)
+ {
+ _bfd_error_handler (_("%pB: warning: BTI turned on by --force-bti when "
+ "all inputs do not have BTI in NOTE section."),
+ bbfd);
+ }
+ }
+
+ return _bfd_aarch64_elf_merge_gnu_properties (info, abfd, aprop,
+ bprop, prop);
+}
/* We use this so we can override certain functions
(though currently we don't). */
#define ELF_MINPAGESIZE 0x1000
#define ELF_COMMONPAGESIZE 0x1000
-#define bfd_elfNN_close_and_cleanup \
+#define bfd_elfNN_close_and_cleanup \
elfNN_aarch64_close_and_cleanup
-#define bfd_elfNN_bfd_free_cached_info \
+#define bfd_elfNN_bfd_free_cached_info \
elfNN_aarch64_bfd_free_cached_info
#define bfd_elfNN_bfd_is_target_special_symbol \
elfNN_aarch64_is_target_special_symbol
-#define bfd_elfNN_bfd_link_hash_table_create \
+#define bfd_elfNN_bfd_link_hash_table_create \
elfNN_aarch64_link_hash_table_create
#define bfd_elfNN_bfd_merge_private_bfd_data \
#define bfd_elfNN_find_nearest_line \
elfNN_aarch64_find_nearest_line
+#define bfd_elfNN_get_synthetic_symtab \
+ elfNN_aarch64_get_synthetic_symtab
+
#define bfd_elfNN_mkobject \
elfNN_aarch64_mkobject
#define elf_backend_finish_dynamic_symbol \
elfNN_aarch64_finish_dynamic_symbol
-#define elf_backend_gc_sweep_hook \
- elfNN_aarch64_gc_sweep_hook
-
#define elf_backend_object_p \
elfNN_aarch64_object_p
-#define elf_backend_output_arch_local_syms \
+#define elf_backend_output_arch_local_syms \
elfNN_aarch64_output_arch_local_syms
#define elf_backend_plt_sym_val \
#define elf_backend_write_section \
elfNN_aarch64_write_section
+#define elf_backend_symbol_processing \
+ elfNN_aarch64_backend_symbol_processing
+
+#define elf_backend_setup_gnu_properties \
+ elfNN_aarch64_link_setup_gnu_properties
+
+#define elf_backend_merge_gnu_properties \
+ elfNN_aarch64_merge_gnu_properties
+
#define elf_backend_can_refcount 1
#define elf_backend_can_gc_sections 1
#define elf_backend_plt_readonly 1
#define elf_backend_want_got_plt 1
#define elf_backend_want_plt_sym 0
+#define elf_backend_want_dynrelro 1
#define elf_backend_may_use_rel_p 0
#define elf_backend_may_use_rela_p 1
#define elf_backend_default_use_rela_p 1
-#define elf_backend_rela_normal 1
+#define elf_backend_rela_normal 1
+#define elf_backend_dtrel_excludes_plt 1
#define elf_backend_got_header_size (GOT_ENTRY_SIZE * 3)
#define elf_backend_default_execstack 0
#define elf_backend_extern_protected_data 1
+#define elf_backend_hash_symbol elf_aarch64_hash_symbol
-#undef elf_backend_obj_attrs_section
+#undef elf_backend_obj_attrs_section
#define elf_backend_obj_attrs_section ".ARM.attributes"
#include "elfNN-target.h"
+
+/* CloudABI support. */
+
+#undef TARGET_LITTLE_SYM
+#define TARGET_LITTLE_SYM aarch64_elfNN_le_cloudabi_vec
+#undef TARGET_LITTLE_NAME
+#define TARGET_LITTLE_NAME "elfNN-littleaarch64-cloudabi"
+#undef TARGET_BIG_SYM
+#define TARGET_BIG_SYM aarch64_elfNN_be_cloudabi_vec
+#undef TARGET_BIG_NAME
+#define TARGET_BIG_NAME "elfNN-bigaarch64-cloudabi"
+
+#undef ELF_OSABI
+#define ELF_OSABI ELFOSABI_CLOUDABI
+
+#undef elfNN_bed
+#define elfNN_bed elfNN_aarch64_cloudabi_bed
+
+#include "elfNN-target.h"