X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=bfd%2Felfnn-aarch64.c;h=b329273a99047e93a10e2d53ab5dc4584cc44a2e;hb=50e03d47b77d5730f96f6b6bb66187654e66c797;hp=f3489d538141b9295985922f5ae0f3cb388b70c8;hpb=3ebe65c0ff9f8f76c9971b1cc078273298f0c693;p=binutils-gdb.git diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c index f3489d53814..b329273a990 100644 --- a/bfd/elfnn-aarch64.c +++ b/bfd/elfnn-aarch64.c @@ -1,5 +1,5 @@ /* 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. @@ -228,7 +228,6 @@ || (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_TLSIE_MOVW_GOTTPREL_G1 \ || (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) @@ -340,8 +339,8 @@ static reloc_howto_type elfNN_aarch64_howto_table[] = /* 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 */ @@ -354,7 +353,6 @@ static reloc_howto_type elfNN_aarch64_howto_table[] = 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) */ @@ -368,7 +366,6 @@ static reloc_howto_type elfNN_aarch64_howto_table[] = 0, /* src_mask */ 0, /* dst_mask */ FALSE), /* pcrel_offset */ -#endif /* .xword: (S+A) */ HOWTO64 (AARCH64_R (ABS64), /* type */ @@ -576,7 +573,7 @@ static reloc_howto_type elfNN_aarch64_howto_table[] = 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 */ @@ -591,7 +588,7 @@ static reloc_howto_type elfNN_aarch64_howto_table[] = 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 */ @@ -606,7 +603,7 @@ static reloc_howto_type elfNN_aarch64_howto_table[] = 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 */ @@ -2290,6 +2287,9 @@ struct elf_aarch64_link_hash_table /* 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; @@ -2640,34 +2640,21 @@ aarch64_select_branch_stub (bfd_vma value, bfd_vma place) /* 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); @@ -2846,8 +2833,8 @@ _bfd_aarch64_add_stub_entry_in_group (const char *stub_name, TRUE, FALSE); if (stub_entry == NULL) { - (*_bfd_error_handler) (_("%s: cannot create stub entry %s"), - section->owner, stub_name); + _bfd_error_handler (_("%s: cannot create stub entry %s"), + section->owner, stub_name); return NULL; } @@ -2874,7 +2861,7 @@ _bfd_aarch64_add_stub_entry_after (const char *stub_name, 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; } @@ -4143,8 +4130,8 @@ elfNN_aarch64_size_stubs (bfd *output_bfd, } /* 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; @@ -4175,7 +4162,7 @@ elfNN_aarch64_size_stubs (bfd *output_bfd, 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; @@ -4348,7 +4335,8 @@ bfd_elfNN_aarch64_set_options (struct bfd *output_bfd, int no_enum_warn, int no_wchar_warn, int pic_veneer, int fix_erratum_835769, - int fix_erratum_843419) + int fix_erratum_843419, + int no_apply_dynamic_relocs) { struct elf_aarch64_link_hash_table *globals; @@ -4357,6 +4345,7 @@ bfd_elfNN_aarch64_set_options (struct bfd *output_bfd, 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; @@ -4494,11 +4483,6 @@ aarch64_tls_transition_without_check (bfd_reloc_code_real_type r_type, return is_local ? BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2 : BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1; - - case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1: - return is_local - ? BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2 - : r_type; #endif default: @@ -4775,9 +4759,9 @@ make_branch_to_erratum_835769_stub (struct bfd_hash_entry *gen_entry, 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; @@ -4856,7 +4840,7 @@ _bfd_aarch64_erratum_843419_branch_to_stub (struct bfd_hash_entry *gen_entry, 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); @@ -4909,7 +4893,9 @@ elfNN_aarch64_write_section (bfd *output_bfd ATTRIBUTE_UNUSED, 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, @@ -4930,7 +4916,6 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto, 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; @@ -4947,17 +4932,6 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto, 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; @@ -4995,7 +4969,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto, else name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, NULL); - (*_bfd_error_handler) + _bfd_error_handler (_("%B: relocation %s against STT_GNU_IFUNC " "symbol `%s' isn't handled by %s"), input_bfd, howto->name, name, __FUNCTION__); @@ -5010,7 +4984,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto, else name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, NULL); - (*_bfd_error_handler) + _bfd_error_handler (_("%B: relocation %s against STT_GNU_IFUNC " "symbol `%s' has non-zero addend: %d"), input_bfd, howto->name, name, rel->r_addend); @@ -5227,6 +5201,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto, 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; } @@ -5286,15 +5261,28 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto, /* 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); @@ -5316,7 +5304,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto, { int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START; - (*_bfd_error_handler) + _bfd_error_handler (_("%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, @@ -5324,6 +5312,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto, bfd_set_error (bfd_error_bad_value); return FALSE; } + /* Fall through. */ case BFD_RELOC_AARCH64_16: #if ARCH_SIZE == 64 @@ -5382,7 +5371,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto, if (locals == NULL) { int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START; - (*_bfd_error_handler) + _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); @@ -5450,7 +5439,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto, if (locals == NULL) { int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START; - (*_bfd_error_handler) + _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); @@ -5633,8 +5622,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto, static bfd_reloc_status_type elfNN_aarch64_tls_relax (struct elf_aarch64_link_hash_table *globals, bfd *input_bfd, bfd_byte *contents, - Elf_Internal_Rela *rel, struct elf_link_hash_entry *h, - bfd_vma relocation ATTRIBUTE_UNUSED) + Elf_Internal_Rela *rel, struct elf_link_hash_entry *h) { bfd_boolean is_local = h == NULL; unsigned int r_type = ELFNN_R_TYPE (rel->r_info); @@ -5800,47 +5788,6 @@ elfNN_aarch64_tls_relax (struct elf_aarch64_link_hash_table *globals, case BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC: return bfd_reloc_continue; - - case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1: - if (is_local) - { - /* Large IE->LE relaxation: - mrs tp, tpidr_el0 - movz tx, #:gottprel_g1:var => movz tx, #:tprel_g2:var, lsl #32 - movk tx, #:gottprel_g0_nc:var => movk tx, #:tprel_g1_nc:var, lsl #16 - ldr tx, [gp, tx] => movk tx, #:tprel_g0_nc:var - add tx, tx, tp - */ - uint32_t value; - BFD_ASSERT (ELFNN_R_TYPE (rel[1].r_info) - == AARCH64_R (TLSIE_MOVW_GOTTPREL_G0_NC)); - BFD_ASSERT (rel->r_offset + 4 == rel[1].r_offset); - - value = (relocation & ~(bfd_vma) 0xffffffff) >> 32; - insn = bfd_getl32 (contents + rel->r_offset); - insn &= 0xff80001f; - insn |= (0x400000 + (value << 5)); - bfd_putl32 (insn, contents + rel->r_offset + 0); - - value = (relocation & (bfd_vma) 0xffff0000) >> 16; - insn = bfd_getl32 (contents + rel->r_offset + 4); - insn &= 0xff80001f; - insn |= (0x200000 + (value << 5)); - bfd_putl32 (insn, contents + rel->r_offset + 4); - - value = relocation & (bfd_vma) 0xffff; - insn = bfd_getl32 (contents + rel->r_offset + 4); - insn &= 0xff80001f; - insn |= (value << 5); - bfd_putl32 (insn, contents + rel->r_offset + 8); - - /* Relocations are already resolved here. */ - rel->r_info = ELFNN_R_INFO (STN_UNDEF, R_AARCH64_NONE); - rel[1].r_info = ELFNN_R_INFO (STN_UNDEF, R_AARCH64_NONE); - return bfd_reloc_ok; - } - - return bfd_reloc_continue; #endif case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19: @@ -6094,7 +6041,7 @@ elfNN_aarch64_relocate_section (bfd *output_bfd, if (howto == NULL) { - (*_bfd_error_handler) + _bfd_error_handler (_("%B: unrecognized relocation (0x%x) in section `%A'"), input_bfd, input_section, r_type); return FALSE; @@ -6117,13 +6064,10 @@ elfNN_aarch64_relocate_section (bfd *output_bfd, 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); @@ -6178,7 +6122,7 @@ elfNN_aarch64_relocate_section (bfd *output_bfd, || h->root.type == bfd_link_hash_defweak) && IS_AARCH64_TLS_RELOC (bfd_r_type) != (sym_type == STT_TLS)) { - (*_bfd_error_handler) + _bfd_error_handler ((sym_type == STT_TLS ? _("%B(%A+0x%lx): %s used with TLS symbol %s") : _("%B(%A+0x%lx): %s used with non-TLS symbol %s")), @@ -6199,8 +6143,7 @@ elfNN_aarch64_relocate_section (bfd *output_bfd, howto = elfNN_aarch64_howto_from_bfd_reloc (bfd_r_type); BFD_ASSERT (howto != NULL); r_type = howto->type; - r = elfNN_aarch64_tls_relax (globals, input_bfd, contents, rel, h, - relocation - tpoff_base (info)); + r = elfNN_aarch64_tls_relax (globals, input_bfd, contents, rel, h); unresolved_reloc = 0; } else @@ -6441,10 +6384,6 @@ elfNN_aarch64_relocate_section (bfd *output_bfd, 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. */ @@ -6454,7 +6393,7 @@ elfNN_aarch64_relocate_section (bfd *output_bfd, && _bfd_elf_section_offset (output_bfd, info, input_section, +rel->r_offset) != (bfd_vma) - 1) { - (*_bfd_error_handler) + _bfd_error_handler (_ ("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"), input_bfd, input_section, (long) rel->r_offset, howto->name, @@ -6470,10 +6409,9 @@ elfNN_aarch64_relocate_section (bfd *output_bfd, 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) { @@ -6484,13 +6422,39 @@ elfNN_aarch64_relocate_section (bfd *output_bfd, 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: @@ -6511,13 +6475,14 @@ elfNN_aarch64_relocate_section (bfd *output_bfd, 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; @@ -6557,15 +6522,16 @@ elfNN_aarch64_set_private_flags (bfd *abfd, flagword flags) 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)) @@ -7054,8 +7020,7 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info, if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr)) { - (*_bfd_error_handler) (_("%B: bad symbol index: %d"), abfd, - r_symndx); + _bfd_error_handler (_("%B: bad symbol index: %d"), abfd, r_symndx); return FALSE; } @@ -7102,6 +7067,22 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info, 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 @@ -7336,7 +7317,7 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info, if (bfd_link_pic (info)) { int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START; - (*_bfd_error_handler) + _bfd_error_handler (_("%B: relocation %s against `%s' can not be used when making " "a shared object; recompile with -fPIC"), abfd, elfNN_aarch64_howto_table[howto_index].name, @@ -7344,6 +7325,7 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info, 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: @@ -8255,9 +8237,11 @@ elfNN_aarch64_allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h, && 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; } @@ -9062,7 +9046,8 @@ elfNN_aarch64_finish_dynamic_sections (bfd *output_bfd, 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: @@ -9174,7 +9159,7 @@ elfNN_aarch64_finish_dynamic_sections (bfd *output_bfd, { 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; } @@ -9229,6 +9214,40 @@ elfNN_aarch64_plt_sym_val (bfd_vma i, const asection *plt, 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). */ @@ -9368,6 +9387,9 @@ const struct elf_size_info elfNN_aarch64_size_info = #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 @@ -9385,3 +9407,22 @@ const struct elf_size_info elfNN_aarch64_size_info = #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"