/* AArch64-specific support for NN-bit ELF.
- Copyright (C) 2009-2015 Free Software Foundation, Inc.
+ Copyright (C) 2009-2017 Free Software Foundation, Inc.
Contributed by ARM Ltd.
This file is part of BFD, the Binary File Descriptor library.
((R_TYPE) == BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21 \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_ADR_PREL21 \
+ || (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_LD32_GOTTPREL_LO12_NC \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19 \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_HI12 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12_NC \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21 \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADR_PREL21 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G2 \
|| (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_TLS_TPREL \
|| IS_AARCH64_TLSDESC_RELOC ((R_TYPE)))
+#define IS_AARCH64_TLS_RELAX_RELOC(R_TYPE) \
+ ((R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADD \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC \
+ || (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 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21 \
+ || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADR_PREL21)
+
#define IS_AARCH64_TLSDESC_RELOC(R_TYPE) \
((R_TYPE) == BFD_RELOC_AARCH64_TLSDESC \
|| (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADD \
#define PLT_SMALL_ENTRY_SIZE (16)
#define PLT_TLSDESC_ENTRY_SIZE (32)
-/* Encoding of the nop instruction */
+/* Encoding of the nop instruction. */
#define INSN_NOP 0xd503201f
#define aarch64_compute_jump_table_size(htab) \
/* 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 */
0xffc, /* dst_mask */
FALSE), /* pcrel_offset */
+ /* Lower 16 bits of GOT offset for the symbol. */
+ HOWTO64 (AARCH64_R (MOVW_GOTOFF_G0_NC), /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_GOTOFF_G0_NC), /* name */
+ FALSE, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* Higher 16 bits of GOT offset for the symbol. */
+ HOWTO64 (AARCH64_R (MOVW_GOTOFF_G1), /* type */
+ 16, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (MOVW_GOTOFF_G1), /* name */
+ FALSE, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
/* LD64: GOT offset for the symbol. */
HOWTO64 (AARCH64_R (LD64_GOTOFF_LO15), /* type */
3, /* rightshift */
0xfff, /* dst_mask */
FALSE), /* pcrel_offset */
- HOWTO64 (AARCH64_R (TLSIE_MOVW_GOTTPREL_G1), /* type */
- 16, /* rightshift */
+ /* Lower 16 bits of GOT offset to tls_index. */
+ HOWTO64 (AARCH64_R (TLSGD_MOVW_G0_NC), /* type */
+ 0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
- AARCH64_R_STR (TLSIE_MOVW_GOTTPREL_G1), /* name */
+ AARCH64_R_STR (TLSGD_MOVW_G0_NC), /* name */
FALSE, /* partial_inplace */
0xffff, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
- HOWTO64 (AARCH64_R (TLSIE_MOVW_GOTTPREL_G0_NC), /* type */
- 0, /* rightshift */
+ /* Higher 16 bits of GOT offset to tls_index. */
+ HOWTO64 (AARCH64_R (TLSGD_MOVW_G1), /* type */
+ 16, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
16, /* 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 (TLSIE_MOVW_GOTTPREL_G0_NC), /* name */
+ AARCH64_R_STR (TLSGD_MOVW_G1), /* name */
FALSE, /* partial_inplace */
0xffff, /* src_mask */
0xffff, /* dst_mask */
0x1ffffc, /* dst_mask */
FALSE), /* pcrel_offset */
+ HOWTO64 (AARCH64_R (TLSIE_MOVW_GOTTPREL_G0_NC), /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSIE_MOVW_GOTTPREL_G0_NC), /* name */
+ FALSE, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO64 (AARCH64_R (TLSIE_MOVW_GOTTPREL_G1), /* type */
+ 16, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSIE_MOVW_GOTTPREL_G1), /* name */
+ FALSE, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* ADD: bit[23:12] of byte offset to module TLS base address. */
+ HOWTO (AARCH64_R (TLSLD_ADD_DTPREL_HI12), /* type */
+ 12, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 12, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_ADD_DTPREL_HI12), /* name */
+ FALSE, /* partial_inplace */
+ 0xfff, /* src_mask */
+ 0xfff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
/* Unsigned 12 bit byte offset to module TLS base address. */
HOWTO (AARCH64_R (TLSLD_ADD_DTPREL_LO12), /* type */
0, /* rightshift */
0xfff, /* dst_mask */
FALSE), /* pcrel_offset */
+ /* No overflow check version of BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12. */
+ HOWTO (AARCH64_R (TLSLD_ADD_DTPREL_LO12_NC), /* type */
+ 0, /* 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 (TLSLD_ADD_DTPREL_LO12_NC), /* name */
+ FALSE, /* partial_inplace */
+ 0xfff, /* src_mask */
+ 0xfff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
/* ADD: GOT offset G(S) & 0xff8 [no overflow check] */
HOWTO (AARCH64_R (TLSLD_ADD_LO12_NC), /* type */
0, /* rightshift */
0x1fffff, /* dst_mask */
TRUE), /* pcrel_offset */
+ /* LD/ST16: bit[11:1] of byte offset to module TLS base address. */
+ HOWTO64 (AARCH64_R (TLSLD_LDST16_DTPREL_LO12), /* type */
+ 1, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 11, /* bitsize */
+ FALSE, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_LDST16_DTPREL_LO12), /* name */
+ FALSE, /* partial_inplace */
+ 0x1ffc00, /* src_mask */
+ 0x1ffc00, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* Same as BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12, but no overflow check. */
+ HOWTO64 (AARCH64_R (TLSLD_LDST16_DTPREL_LO12_NC), /* type */
+ 1, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 11, /* bitsize */
+ FALSE, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_LDST16_DTPREL_LO12_NC), /* name */
+ FALSE, /* partial_inplace */
+ 0x1ffc00, /* src_mask */
+ 0x1ffc00, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* LD/ST32: bit[11:2] of byte offset to module TLS base address. */
+ HOWTO64 (AARCH64_R (TLSLD_LDST32_DTPREL_LO12), /* type */
+ 2, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 10, /* bitsize */
+ FALSE, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_LDST32_DTPREL_LO12), /* name */
+ FALSE, /* partial_inplace */
+ 0x3ffc00, /* src_mask */
+ 0x3ffc00, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* Same as BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12, but no overflow check. */
+ HOWTO64 (AARCH64_R (TLSLD_LDST32_DTPREL_LO12_NC), /* type */
+ 2, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 10, /* bitsize */
+ FALSE, /* pc_relative */
+ 10, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_LDST32_DTPREL_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. */
+ HOWTO64 (AARCH64_R (TLSLD_LDST64_DTPREL_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 (TLSLD_LDST64_DTPREL_LO12), /* name */
+ FALSE, /* partial_inplace */
+ 0x3ffc00, /* src_mask */
+ 0x3ffc00, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* Same as BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12, but no overflow check. */
+ HOWTO64 (AARCH64_R (TLSLD_LDST64_DTPREL_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 (TLSLD_LDST64_DTPREL_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. */
+ HOWTO64 (AARCH64_R (TLSLD_LDST8_DTPREL_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 (TLSLD_LDST8_DTPREL_LO12), /* name */
+ FALSE, /* partial_inplace */
+ 0x3ffc00, /* src_mask */
+ 0x3ffc00, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* Same as BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12, but no overflow check. */
+ HOWTO64 (AARCH64_R (TLSLD_LDST8_DTPREL_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 (TLSLD_LDST8_DTPREL_LO12_NC), /* name */
+ FALSE, /* partial_inplace */
+ 0x3ffc00, /* src_mask */
+ 0x3ffc00, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* MOVZ: bit[15:0] of byte offset to module TLS base address. */
+ HOWTO (AARCH64_R (TLSLD_MOVW_DTPREL_G0), /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_MOVW_DTPREL_G0), /* name */
+ FALSE, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* No overflow check version of BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0. */
+ HOWTO (AARCH64_R (TLSLD_MOVW_DTPREL_G0_NC), /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_MOVW_DTPREL_G0_NC), /* name */
+ FALSE, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* MOVZ: bit[31:16] of byte offset to module TLS base address. */
+ HOWTO (AARCH64_R (TLSLD_MOVW_DTPREL_G1), /* type */
+ 16, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_MOVW_DTPREL_G1), /* name */
+ FALSE, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* No overflow check version of BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1. */
+ HOWTO64 (AARCH64_R (TLSLD_MOVW_DTPREL_G1_NC), /* type */
+ 16, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_MOVW_DTPREL_G1_NC), /* name */
+ FALSE, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* MOVZ: bit[47:32] of byte offset to module TLS base address. */
+ HOWTO64 (AARCH64_R (TLSLD_MOVW_DTPREL_G2), /* type */
+ 32, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ AARCH64_R_STR (TLSLD_MOVW_DTPREL_G2), /* name */
+ FALSE, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
HOWTO64 (AARCH64_R (TLSLE_MOVW_TPREL_G2), /* type */
32, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
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 */
/* 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. */
bfd_size_type plt_entry_size;
- /* Short-cuts to get to dynamic linker sections. */
- asection *sdynbss;
- asection *srelbss;
-
/* Small local sym cache. */
struct sym_cache sym_cache;
/* Assorted information used by elfNN_aarch64_size_stubs. */
unsigned int bfd_count;
- int top_index;
+ unsigned int top_index;
asection **input_list;
/* The offset into splt of the PLT entry for the TLS descriptor
/* 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)
- 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);
- if (via_plt_p)
+ if (st_type != STT_FUNC
+ && (sym_sec == input_sec))
return stub_type;
/* Determine where the call point is. */
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 (_("%s: 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;
}
{
bfd *input_bfd;
unsigned int bfd_count;
- int top_id, top_index;
+ unsigned int top_id, top_index;
asection *section;
asection **input_list, **list;
bfd_size_type amt;
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,
}
/* Determine what (if any) linker stub is needed. */
- stub_type = aarch64_type_of_stub
- (info, section, irela, st_type, hash, destination);
+ stub_type = aarch64_type_of_stub (section, irela, sym_sec,
+ st_type, destination);
if (stub_type == aarch64_stub_none)
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;
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)
{
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;
BFD_ASSERT (basegot != NULL);
off = h->got.offset;
BFD_ASSERT (off != (bfd_vma) - 1);
- if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
- || (info->shared
+ if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)
+ || (bfd_link_pic (info)
&& SYMBOL_REFERENCES_LOCAL (info, h))
|| (ELF_ST_VISIBILITY (h->other)
&& h->root.type == bfd_link_hash_undefweak))
? 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:
case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC:
case BFD_RELOC_AARCH64_TLSDESC_CALL:
/* Instructions with these relocations will become NOPs. */
return BFD_RELOC_AARCH64_NONE;
+ case BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21:
+ 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_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:
return GOT_NORMAL;
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_TLSLD_ADD_LO12_NC:
case BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21:
case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21:
return GOT_TLS_GD;
+ case BFD_RELOC_AARCH64_TLSDESC_ADD:
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_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:
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:
return GOT_TLS_IE;
- 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_MOVW_TPREL_G0:
- case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
- case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1:
- case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
- case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2:
- return GOT_UNKNOWN;
-
default:
break;
}
unsigned int symbol_got_type;
unsigned int reloc_got_type;
- if (! IS_AARCH64_TLS_RELOC (r_type))
+ if (! IS_AARCH64_TLS_RELAX_RELOC (r_type))
return FALSE;
symbol_got_type = elfNN_aarch64_symbol_got_type (h, input_bfd, r_symndx);
if (symbol_got_type == GOT_TLS_IE && GOT_TLS_GD_ANY_P (reloc_got_type))
return TRUE;
- if (info->shared)
+ if (bfd_link_pic (info))
return FALSE;
if (h && h->root.type == bfd_link_hash_undefweak)
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
+ (_("%B: error: Erratum 835769 stub out "
+ "of range (input file too large)"), abfd);
target = stub_entry->target_value;
branch_insn = 0x14000000;
abfd = stub_entry->target_section->owner;
if (!aarch64_valid_branch_p (veneer_entry_loc, veneered_insn_loc))
- (*_bfd_error_handler)
+ _bfd_error_handler
(_("%B: error: Erratum 843419 stub out "
"of range (input file too large)"), abfd);
return FALSE;
}
-/* Perform a relocation as part of a final link. */
+/* 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;
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;
else
name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym,
NULL);
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: relocation %s against STT_GNU_IFUNC "
"symbol `%s' isn't handled by %s"), input_bfd,
howto->name, name, __FUNCTION__);
else
name = bfd_elf_sym_name (input_bfd, symtab_hdr,
sym, NULL);
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: relocation %s against STT_GNU_IFUNC "
"symbol `%s' has non-zero addend: %d"),
input_bfd, howto->name, name, rel->r_addend);
/* Generate dynamic relocation only when there is a
non-GOT reference in a shared object. */
- if (info->shared && h->non_got_ref)
+ if (bfd_link_pic (info) && h->non_got_ref)
{
Elf_Internal_Rela outrel;
asection *sreloc;
if (h->dynindx == -1
|| h->forced_local
- || info->executable)
+ || bfd_link_executable (info))
{
/* This symbol is resolved locally. */
outrel.r_info = ELFNN_R_INFO (0, AARCH64_R (IRELATIVE));
case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14:
case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15:
+ case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC:
+ case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1:
+ case BFD_RELOC_AARCH64_LD64_GOTOFF_LO15:
case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
base_got = globals->root.sgot;
off = h->got.offset;
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)
- addend = (globals->root.sgot->output_section->vma
- + globals->root.sgot->output_offset);
+
+ 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;
+ }
+
value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value,
addend, weak_undef_p);
return _bfd_aarch64_elf_put_addend (input_bfd, hit_data, bfd_r_type, howto, value);
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;
/* When generating a shared object or relocatable executable, these
relocations are copied into the output file to be resolved at
run time. */
- if (((info->shared == TRUE) || globals->root.is_relocatable_executable)
+ 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
memset (&outrel, 0, sizeof outrel);
else if (h != NULL
&& h->dynindx != -1
- && (!info->shared || !SYMBOLIC_BIND (info, h) || !h->def_regular))
+ && (!bfd_link_pic (info)
+ || !(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;
}
/* If the call goes through a PLT entry, make sure to
check distance to the right destination address. */
if (via_plt_p)
+ value = (splt->output_section->vma
+ + splt->output_offset + h->plt.offset);
+
+ /* 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 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 = (splt->output_section->vma
- + splt->output_offset + h->plt.offset);
- *unresolved_reloc_p = FALSE;
- }
+ value = (stub_entry->stub_offset
+ + stub_entry->stub_sec->output_offset
+ + stub_entry->stub_sec->output_section->vma);
- /* If the target symbol is global and marked as a function the
- relocation applies a function call or a tail call. In this
- situation we can veneer out of range branches. The veneers
- use IP0 and IP1 hence cannot be used arbitrary out of range
- branches that occur within the body of a function. */
- if (h && h->type == STT_FUNC)
- {
- /* Check if a stub has to be inserted because the destination
- is too far away. */
- if (! aarch64_valid_branch_p (value, place))
- {
- /* The target is out of reach, so redirect the branch to
- the local stub for this function. */
- struct elf_aarch64_stub_hash_entry *stub_entry;
- 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);
- }
+ /* 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);
+ *unresolved_reloc_p = FALSE;
break;
case BFD_RELOC_AARCH64_16_PCREL:
case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
case BFD_RELOC_AARCH64_ADR_LO21_PCREL:
case BFD_RELOC_AARCH64_LD_LO19_PCREL:
- if (info->shared
+ if (bfd_link_pic (info)
&& (input_section->flags & SEC_ALLOC) != 0
&& (input_section->flags & SEC_READONLY) != 0
&& h != NULL
{
int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START;
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: relocation %s against external symbol `%s' can not be used"
" when making a shared object; recompile with -fPIC"),
input_bfd, elfNN_aarch64_howto_table[howto_index].name,
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
+ /* Fall through. */
case BFD_RELOC_AARCH64_16:
#if ARCH_SIZE == 64
if (locals == NULL)
{
int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START;
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: Local symbol descriptor table be NULL when applying "
"relocation %s against local symbol"),
input_bfd, elfNN_aarch64_howto_table[howto_index].name);
{
bfd_put_64 (output_bfd, value, base_got->contents + off);
- if (info->shared)
+ if (bfd_link_pic (info))
{
asection *s;
Elf_Internal_Rela outrel;
elf_append_rela (output_bfd, s, &outrel);
}
- symbol_got_offset_mark (input_bfd, h, r_symndx);
- }
+ symbol_got_offset_mark (input_bfd, h, r_symndx);
+ }
+
+ /* Update the relocation value to GOT entry addr as we have transformed
+ 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)
+ 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;
+
+ 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
+ /* xgettext:c-format */
+ (_("%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)
+ abort ();
+
+ bfd_vma got_entry_addr = (base_got->output_section->vma
+ + base_got->output_offset + off);
- /* Update the relocation value to GOT entry addr as we have transformed
- the direct data access into indirect data access through GOT. */
- value = got_entry_addr;
+ if (!symbol_got_offset_mark_p (input_bfd, h, r_symndx))
+ {
+ bfd_put_64 (output_bfd, value, base_got->contents + off);
- if (bfd_r_type == BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15
- || bfd_r_type == BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14)
- addend = base_got->output_section->vma + base_got->output_offset;
+ 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);
+ }
- value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value,
- addend, weak_undef_p);
- }
+ symbol_got_offset_mark (input_bfd, h, r_symndx);
+ }
+ }
+ /* 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:
*unresolved_reloc_p = FALSE;
break;
+ case BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC:
+ case BFD_RELOC_AARCH64_TLSGD_MOVW_G1:
+ case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC:
+ case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1:
+ if (globals->root.sgot == NULL)
+ return bfd_reloc_notsupported;
+
+ 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_TLSLD_ADD_DTPREL_HI12:
+ case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12:
+ case BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC:
+ case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0:
+ case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0_NC:
+ case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1:
+ case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1_NC:
+ case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G2:
+ value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value,
+ signed_addend - dtpoff_base (info),
+ weak_undef_p);
+ break;
+
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:
*unresolved_reloc_p = FALSE;
break;
- case BFD_RELOC_AARCH64_TLSDESC_ADD:
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_LDR:
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
+
/* 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.
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);
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
- */
+
+ 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;
}
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;
{
/* 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
- */
+ 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
+ adr x0, :tlsgd:var => ldr R0, :gottprel:var
bl __tls_get_addr => mrs x1, tpidr_el0
- nop => add x0, x0, x1
- */
+ 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
+ add x0, #:tlsgd_lo12:var => movk R0, :tprel_g0_nc:var
bl __tls_get_addr => mrs x1, tpidr_el0
- nop => add x0, x1, x0
- */
+ 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]
+ 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:
case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12_NC:
case BFD_RELOC_AARCH64_TLSDESC_CALL:
/* GD->IE/LE relaxation:
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);
}
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 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);
+ 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 (0xd53bd040, contents + rel->r_offset + 0);
+ 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_ADR_PAGE21:
+ /* LD->LE relaxation (small):
+ adrp x0, :tlsldm:x => mrs x0, tpidr_el0
+ */
+ if (is_local)
+ {
+ bfd_putl32 (0xd53bd040, contents + rel->r_offset);
+ 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 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 (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;
if (howto == NULL)
{
- (*_bfd_error_handler)
+ /* xgettext:c-format */
+ _bfd_error_handler
(_("%B: unrecognized relocation (0x%x) in section `%A'"),
input_bfd, input_section, r_type);
return FALSE;
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);
/* Relocate against local STT_GNU_IFUNC symbol. */
- if (!info->relocatable
+ if (!bfd_link_relocatable (info)
&& ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
{
h = elfNN_aarch64_get_local_sym_hash (globals, input_bfd,
RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
rel, 1, relend, howto, 0, contents);
- if (info->relocatable)
+ if (bfd_link_relocatable (info))
continue;
if (h != NULL)
|| 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
+ /* xgettext:c-format */
? _("%B(%A+0x%lx): %s used with TLS symbol %s")
+ /* xgettext:c-format */
: _("%B(%A+0x%lx): %s used with non-TLS symbol %s")),
input_bfd,
input_section, (long) rel->r_offset, howto->name, name);
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_TLSLD_ADD_LO12_NC:
case BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21:
case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21:
indx = h && h->dynindx != -1 ? h->dynindx : 0;
need_relocs =
- (info->shared || indx != 0) &&
+ (bfd_link_pic (info) || indx != 0) &&
(h == NULL
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak);
case BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
case BFD_RELOC_AARCH64_TLSIE_LDNN_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:
if (! symbol_got_offset_mark_p (input_bfd, h, r_symndx))
{
bfd_boolean need_relocs = FALSE;
indx = h && h->dynindx != -1 ? h->dynindx : 0;
need_relocs =
- (info->shared || indx != 0) &&
+ (bfd_link_pic (info) || indx != 0) &&
(h == NULL
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak);
}
break;
- 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_MOVW_TPREL_G0:
- case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
- case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1:
- case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
- case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2:
- break;
-
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_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. */
&& _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'"),
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
input_bfd, input_section, (long) 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);
+
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, "
+ "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))
struct elf_aarch64_local_symbol *locals;
const Elf_Internal_Rela *rel, *relend;
- if (info->relocatable)
+ if (bfd_link_relocatable (info))
return TRUE;
htab = elf_aarch64_hash_table (info);
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_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:
+ 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:
- 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_MOVW_TPREL_G0:
- case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
- case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1:
- case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
- case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2:
if (h != NULL)
{
if (h->got.refcount > 0)
case BFD_RELOC_AARCH64_MOVW_G2_NC:
case BFD_RELOC_AARCH64_MOVW_G3:
case BFD_RELOC_AARCH64_NN:
- if (h != NULL && info->executable)
+ if (h != NULL && bfd_link_executable (info))
{
if (h->plt.refcount > 0)
h->plt.refcount -= 1;
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,
only references to the symbol are via the global offset table.
For such cases we need not do anything here; the relocations will
be handled correctly by relocate_section. */
- if (info->shared)
+ if (bfd_link_pic (info))
return TRUE;
/* If there are no references to this symbol that do not use the
/* 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;
struct elf_aarch64_link_hash_table *htab;
- if (info->relocatable)
+ if (bfd_link_relocatable (info))
return TRUE;
BFD_ASSERT (is_aarch64_elf (abfd));
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 (_("%B: bad symbol index: %d"), abfd, r_symndx);
return FALSE;
}
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
case BFD_RELOC_AARCH64_JUMP26:
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_NN:
if (htab->root.dynobj == NULL)
htab->root.dynobj = abfd;
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;
}
if (h != NULL)
{
- if (!info->shared)
+ if (!bfd_link_pic (info))
h->non_got_ref = 1;
h->plt.refcount += 1;
/* No need to do anything if we're not creating a shared
object. */
- if (! info->shared)
+ if (! bfd_link_pic (info))
break;
{
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_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:
+ 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:
- 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_MOVW_TPREL_G0:
- case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1:
case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2:
case BFD_RELOC_AARCH64_MOVW_G1_NC:
case BFD_RELOC_AARCH64_MOVW_G2_NC:
case BFD_RELOC_AARCH64_MOVW_G3:
- if (info->shared)
+ if (bfd_link_pic (info))
{
int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START;
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%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,
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
+ /* Fall through. */
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 && info->executable)
+ 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
return osi->func (osi->finfo, names[type], &sym, osi->sec, NULL) == 1;
}
-
-
-/* Output mapping symbols for PLT entries associated with H. */
-
-static bfd_boolean
-elfNN_aarch64_output_plt_map (struct elf_link_hash_entry *h, void *inf)
-{
- output_arch_syminfo *osi = (output_arch_syminfo *) inf;
- bfd_vma addr;
-
- if (h->root.type == bfd_link_hash_indirect)
- return TRUE;
-
- if (h->root.type == bfd_link_hash_warning)
- /* When warning symbols are created, they **replace** the "real"
- entry in the hash table, thus we never get to see the real
- symbol in a hash traversal. So look at it now. */
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
- if (h->plt.offset == (bfd_vma) - 1)
- return TRUE;
-
- addr = h->plt.offset;
- if (addr == 32)
- {
- if (!elfNN_aarch64_output_map_sym (osi, AARCH64_MAP_INSN, addr))
- return FALSE;
- }
- return TRUE;
-}
-
-
/* Output a single local symbol for a generated stub. */
static bfd_boolean
if (!htab->root.splt || htab->root.splt->size == 0)
return TRUE;
- /* For now live without mapping symbols for the plt. */
osi.sec_shndx = _bfd_elf_section_from_bfd_section
(output_bfd, htab->root.splt->output_section);
osi.sec = htab->root.splt;
- elf_link_hash_traverse (&htab->root, elfNN_aarch64_output_plt_map,
- (void *) &osi);
+ elfNN_aarch64_output_map_sym (&osi, AARCH64_MAP_INSN, 0);
return TRUE;
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 (!info->shared)
- htab->srelbss = bfd_get_linker_section (dynobj, ".rela.bss");
-
- if (!htab->sdynbss || (!info->shared && !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;
return FALSE;
}
- if (info->shared || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h))
+ if (bfd_link_pic (info) || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h))
{
asection *s = htab->root.splt;
location in the .plt. This is required to make function
pointers compare as equal between the normal executable and
the shared library. */
- if (!info->shared && !h->def_regular)
+ if (!bfd_link_pic (info) && !h->def_regular)
{
h->root.u.def.section = s;
h->root.u.def.value = h->plt.offset;
htab->root.sgot->size += GOT_ENTRY_SIZE;
if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak)
- && (info->shared
+ && (bfd_link_pic (info)
|| WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, 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)
- && (info->shared
+ && (bfd_link_pic (info)
|| indx != 0
|| WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
{
space for pc-relative relocs that have become local due to symbol
visibility changes. */
- if (info->shared)
+ 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.
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;
}
/* 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->root.dynamic_sections_created)
{
- if (info->executable)
+ if (bfd_link_executable (info) && !info->nointerp)
{
s = bfd_get_linker_section (dynobj, ".interp");
if (s == NULL)
{
}
- if (info->shared)
+ if (bfd_link_pic (info))
{
if (got_type & GOT_TLSDESC_GD)
{
|| 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;
}
#define add_dynamic_entry(TAG, VAL) \
_bfd_elf_add_dynamic_entry (info, TAG, VAL)
- if (info->executable)
+ if (bfd_link_executable (info))
{
if (!add_dynamic_entry (DT_DEBUG, 0))
return FALSE;
rela.r_offset = gotplt_entry_address;
if (h->dynindx == -1
- || ((info->executable
+ || ((bfd_link_executable (info)
|| ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
&& h->def_regular
&& h->type == STT_GNU_IFUNC))
{
asection *tls_sec;
- if (info->relocatable)
+ if (bfd_link_relocatable (info))
return TRUE;
tls_sec = elf_hash_table (info)->tls_sec;
/* 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,
/* This symbol has an entry in the procedure linkage table. Set
it up. */
if ((h->dynindx == -1
- && !((h->forced_local || info->executable)
+ && !((h->forced_local || bfd_link_executable (info))
&& h->def_regular
&& h->type == STT_GNU_IFUNC))
|| plt == NULL
if (h->def_regular
&& h->type == STT_GNU_IFUNC)
{
- if (info->shared)
+ if (bfd_link_pic (info))
{
/* Generate R_AARCH64_GLOB_DAT. */
goto do_glob_dat;
return TRUE;
}
}
- else if (info->shared && SYMBOL_REFERENCES_LOCAL (info, h))
+ else if (bfd_link_pic (info) && SYMBOL_REFERENCES_LOCAL (info, h))
{
if (!h->def_regular)
return FALSE;
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;
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
{
if (bfd_is_abs_section (htab->root.sgotplt->output_section))
{
- (*_bfd_error_handler)
+ _bfd_error_handler
(_("discarded output section: `%A'"), htab->root.sgotplt);
return FALSE;
}
return plt->vma + PLT_ENTRY_SIZE + i * PLT_SMALL_ENTRY_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;
+}
+
/* We use this so we can override certain functions
(though currently we don't). */
#define elf_backend_write_section \
elfNN_aarch64_write_section
+#define elf_backend_symbol_processing \
+ elfNN_aarch64_backend_symbol_processing
+
#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_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
#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"