/* AArch64-specific support for NN-bit ELF.
- Copyright (C) 2009-2015 Free Software Foundation, Inc.
+ Copyright (C) 2009-2016 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 \
|| IS_AARCH64_TLSDESC_RELOC ((R_TYPE)))
#define IS_AARCH64_TLS_RELAX_RELOC(R_TYPE) \
- ((R_TYPE) == BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21 \
+ ((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_TLSDESC_ADR_PAGE21 \
- || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21 \
- || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LD_PREL19 \
- || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LDNN_LO12_NC \
- || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_CALL \
- || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADD_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 \
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 */
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 */
/* 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);
}
/* 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;
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;
? 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;
default:
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;
/* 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);
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)
+ (_("%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);
+
+ 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);
+ }
+ }
+
+ /* 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_TLSGD_ADR_PAGE21:
case BFD_RELOC_AARCH64_TLSGD_ADR_PREL21:
*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:
*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;
}
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 (0xd2c00000, contents + rel->r_offset + 0);
+ bfd_putl32 (0xf2a00000, contents + rel->r_offset + 4);
+ bfd_putl32 (0xf2800000, contents + rel->r_offset + 8);
+ bfd_putl32 (0xd53bd041, contents + rel->r_offset + 12);
+ bfd_putl32 (0x8b000020, 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 (0x58000000, contents + rel->r_offset + 8);
+ bfd_putl32 (0xd53bd041, contents + rel->r_offset + 12);
+ bfd_putl32 (0x8b000020, 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;
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 x0, #:tprel_g0_nc:var
+ */
+ bfd_putl32 (0xf2800000, contents + rel->r_offset);
+ return bfd_reloc_continue;
+ }
+ else
+ {
+ /* GD->IE relaxation:
+ ldr xd, [gp, xn] => ldr x0, [gp, xn]
+ */
+ insn = bfd_getl32 (contents + rel->r_offset);
+ insn &= 0xffffffe0;
+ bfd_putl32 (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 x0, #:tprel_g1_nc:var, lsl #16
+ GD->IE relaxation:
+ movk xd, #:tlsdesc_off_g0_nc:var => movk xd, #:gottprel_g0_nc:var
+ */
+ if (is_local)
+ bfd_putl32 (0xf2a00000, 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 x0, #:tprel_g2:var, lsl #32
+ */
+ bfd_putl32 (0xd2c00000, contents + rel->r_offset);
+ return bfd_reloc_continue;
+ }
+ else
+ {
+ /* GD->IE relaxation:
+ movz xd, #:tlsdesc_off_g1:var => movz xd, #:gottprel_g1:var, lsl #16
+ */
+ insn = bfd_getl32 (contents + rel->r_offset);
+ bfd_putl32 (0xd2a00000 | (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
}
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
+ */
+ 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 (0x91004000, 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 x0, x0, TCB_SIZE
+ bl __tls_get_addr => nop
+ */
+ 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);
+ return bfd_reloc_ok;
+ }
+ return bfd_reloc_continue;
+
default:
return bfd_reloc_continue;
}
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:
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;
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. */
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:
break;
}
}
+
+ if (!save_addend)
+ addend = 0;
}
return TRUE;
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:
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;
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_MOVW_TPREL_G1:
+ case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
+ case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2:
{
unsigned got_type;
unsigned old_got_type;
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;
&& 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);
if (htab->root.dynamic_sections_created)
{
- if (bfd_link_executable (info))
+ if (bfd_link_executable (info) && !info->nointerp)
{
s = bfd_get_linker_section (dynobj, ".interp");
if (s == NULL)
#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"