X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gold%2Faarch64.cc;h=33485de61f6cb55abfce9e35b0389f8d384b8f52;hb=0f977b7715ee9aa8959e08c00b6d2c47a40e6504;hp=c9bb6b730d3097d380c52cbb8eee6b53f270849b;hpb=6bf56e7482e220ff98655b5285736a37dd602c17;p=binutils-gdb.git diff --git a/gold/aarch64.cc b/gold/aarch64.cc index c9bb6b730d3..33485de61f6 100644 --- a/gold/aarch64.cc +++ b/gold/aarch64.cc @@ -1,6 +1,6 @@ // aarch64.cc -- aarch64 target support for gold. -// Copyright (C) 2014-2017 Free Software Foundation, Inc. +// Copyright (C) 2014-2021 Free Software Foundation, Inc. // Written by Jing Yu and Han Shen . // This file is part of gold. @@ -110,6 +110,10 @@ public: is_adrp(const Insntype insn) { return (insn & 0x9F000000) == 0x90000000; } + static bool + is_mrs_tpidr_el0(const Insntype insn) + { return (insn & 0xFFFFFFE0) == 0xd53bd040; } + static unsigned int aarch64_rm(const Insntype insn) { return aarch64_bits(insn, 16, 5); } @@ -266,7 +270,7 @@ public: uint32_t v = 0; uint32_t opc_v = 0; - /* Bail out quickly if INSN doesn't fall into the the load-store + /* Bail out quickly if INSN doesn't fall into the load-store encoding space. */ if (!aarch64_ldst (insn)) return false; @@ -926,7 +930,7 @@ private: // Erratum stub class. An erratum stub differs from a reloc stub in that for // each erratum occurrence, we generate an erratum stub. We never share erratum -// stubs, whereas for reloc stubs, different branches insns share a single reloc +// stubs, whereas for reloc stubs, different branch insns share a single reloc // stub as long as the branch targets are the same. (More to the point, reloc // stubs can be shared because they're used to reach a specific target, whereas // erratum stubs branch back to the original control flow.) @@ -1027,6 +1031,18 @@ public: set_erratum_address(AArch64_address addr) { this->erratum_address_ = addr; } + // Later relaxation passes of may alter the recorded erratum and destination + // address. Given an up to date output section address of shidx_ in + // relobj_ we can derive the erratum_address and destination address. + void + update_erratum_address(AArch64_address output_section_addr) + { + const int BPI = AArch64_insn_utilities::BYTES_PER_INSN; + AArch64_address updated_addr = output_section_addr + this->sh_offset_; + this->set_erratum_address(updated_addr); + this->set_destination_address(updated_addr + BPI); + } + // Comparator used to group Erratum_stubs in a set by (obj, shndx, // sh_offset). We do not include 'type' in the calculation, because there is // at most one stub type at (obj, shndx, sh_offset). @@ -1045,6 +1061,17 @@ public: return this->sh_offset_ < k.sh_offset_; } + void + invalidate_erratum_stub() + { + gold_assert(this->erratum_insn_ != invalid_insn); + this->erratum_insn_ = invalid_insn; + } + + bool + is_invalidated_erratum_stub() + { return this->erratum_insn_ == invalid_insn; } + protected: virtual void do_write(unsigned char*, section_size_type); @@ -1086,7 +1113,7 @@ public: private: // Section offset of "adrp". (We do not need a "adrp_shndx_" field, because we - // can can obtain it from its parent.) + // can obtain it from its parent.) const unsigned int adrp_sh_offset_; }; @@ -1342,7 +1369,8 @@ Reloc_stub::stub_type_for_reloc( return ST_LONG_BRANCH_ABS; } -// A class to hold stubs for the ARM target. +// A class to hold stubs for the ARM target. This contains 2 different types of +// stubs - reloc stubs and erratum stubs. template class Stub_table : public Output_data @@ -1434,14 +1462,18 @@ class Stub_table : public Output_data return (p != this->reloc_stubs_.end()) ? p->second : NULL; } - // Relocate stubs in this stub table. + // Relocate reloc stubs in this stub table. This does not relocate erratum stubs. void - relocate_stubs(const The_relocate_info*, - The_target_aarch64*, - Output_section*, - unsigned char*, - AArch64_address, - section_size_type); + relocate_reloc_stubs(const The_relocate_info*, + The_target_aarch64*, + Output_section*, + unsigned char*, + AArch64_address, + section_size_type); + + // Relocate an erratum stub. + void + relocate_erratum_stub(The_erratum_stub*, unsigned char*); // Update data size at the end of a relaxation pass. Return true if data size // is different from that of the previous relaxation pass. @@ -1481,15 +1513,15 @@ class Stub_table : public Output_data { this->set_data_size(this->current_data_size()); } private: - // Relocate one stub. + // Relocate one reloc stub. void - relocate_stub(The_reloc_stub*, - const The_relocate_info*, - The_target_aarch64*, - Output_section*, - unsigned char*, - AArch64_address, - section_size_type); + relocate_reloc_stub(The_reloc_stub*, + const The_relocate_info*, + The_target_aarch64*, + Output_section*, + unsigned char*, + AArch64_address, + section_size_type); private: // Owner of this stub table. @@ -1589,76 +1621,85 @@ Stub_table::add_reloc_stub( } -// Relocate all stubs in this stub table. +// Relocate an erratum stub. template void Stub_table:: -relocate_stubs(const The_relocate_info* relinfo, - The_target_aarch64* target_aarch64, - Output_section* output_section, - unsigned char* view, - AArch64_address address, - section_size_type view_size) +relocate_erratum_stub(The_erratum_stub* estub, + unsigned char* view) { - // "view_size" is the total size of the stub_table. - gold_assert(address == this->address() && - view_size == static_cast(this->data_size())); - for(Reloc_stub_map_const_iter p = this->reloc_stubs_.begin(); - p != this->reloc_stubs_.end(); ++p) - relocate_stub(p->second, relinfo, target_aarch64, output_section, - view, address, view_size); - // Just for convenience. const int BPI = AArch64_insn_utilities::BYTES_PER_INSN; - // Now 'relocate' erratum stubs. - for(Erratum_stub_set_iter i = this->erratum_stubs_.begin(); - i != this->erratum_stubs_.end(); ++i) + gold_assert(!estub->is_invalidated_erratum_stub()); + AArch64_address stub_address = this->erratum_stub_address(estub); + // The address of "b" in the stub that is to be "relocated". + AArch64_address stub_b_insn_address; + // Branch offset that is to be filled in "b" insn. + int b_offset = 0; + switch (estub->type()) { - AArch64_address stub_address = this->erratum_stub_address(*i); - // The address of "b" in the stub that is to be "relocated". - AArch64_address stub_b_insn_address; - // Branch offset that is to be filled in "b" insn. - int b_offset = 0; - switch ((*i)->type()) - { - case ST_E_843419: - case ST_E_835769: - // The 1st insn of the erratum could be a relocation spot, - // in this case we need to fix it with - // "(*i)->erratum_insn()". - elfcpp::Swap<32, big_endian>::writeval( - view + (stub_address - this->address()), - (*i)->erratum_insn()); - // For the erratum, the 2nd insn is a b-insn to be patched - // (relocated). - stub_b_insn_address = stub_address + 1 * BPI; - b_offset = (*i)->destination_address() - stub_b_insn_address; - AArch64_relocate_functions::construct_b( - view + (stub_b_insn_address - this->address()), - ((unsigned int)(b_offset)) & 0xfffffff); - break; - default: - gold_unreachable(); - break; - } + case ST_E_843419: + case ST_E_835769: + // The 1st insn of the erratum could be a relocation spot, + // in this case we need to fix it with + // "(*i)->erratum_insn()". + elfcpp::Swap<32, big_endian>::writeval( + view + (stub_address - this->address()), + estub->erratum_insn()); + // For the erratum, the 2nd insn is a b-insn to be patched + // (relocated). + stub_b_insn_address = stub_address + 1 * BPI; + b_offset = estub->destination_address() - stub_b_insn_address; + AArch64_relocate_functions::construct_b( + view + (stub_b_insn_address - this->address()), + ((unsigned int)(b_offset)) & 0xfffffff); + break; + default: + gold_unreachable(); + break; } + estub->invalidate_erratum_stub(); } -// Relocate one stub. This is a helper for Stub_table::relocate_stubs(). +// Relocate only reloc stubs in this stub table. This does not relocate erratum +// stubs. template void Stub_table:: -relocate_stub(The_reloc_stub* stub, - const The_relocate_info* relinfo, - The_target_aarch64* target_aarch64, - Output_section* output_section, - unsigned char* view, - AArch64_address address, - section_size_type view_size) +relocate_reloc_stubs(const The_relocate_info* relinfo, + The_target_aarch64* target_aarch64, + Output_section* output_section, + unsigned char* view, + AArch64_address address, + section_size_type view_size) +{ + // "view_size" is the total size of the stub_table. + gold_assert(address == this->address() && + view_size == static_cast(this->data_size())); + for(Reloc_stub_map_const_iter p = this->reloc_stubs_.begin(); + p != this->reloc_stubs_.end(); ++p) + relocate_reloc_stub(p->second, relinfo, target_aarch64, output_section, + view, address, view_size); +} + + +// Relocate one reloc stub. This is a helper for +// Stub_table::relocate_reloc_stubs(). + +template +void +Stub_table:: +relocate_reloc_stub(The_reloc_stub* stub, + const The_relocate_info* relinfo, + The_target_aarch64* target_aarch64, + Output_section* output_section, + unsigned char* view, + AArch64_address address, + section_size_type view_size) { // "offset" is the offset from the beginning of the stub_table. section_size_type offset = stub->offset(); @@ -1666,8 +1707,8 @@ relocate_stub(The_reloc_stub* stub, // "view_size" is the total size of the stub_table. gold_assert(offset + stub_size <= view_size); - target_aarch64->relocate_stub(stub, relinfo, output_section, - view + offset, address + offset, view_size); + target_aarch64->relocate_reloc_stub(stub, relinfo, output_section, + view + offset, address + offset, view_size); } @@ -1825,15 +1866,17 @@ class AArch64_relobj : public Sized_relobj_file Stringpool_template*); private: - // Fix all errata in the object. + // Fix all errata in the object, and for each erratum, relocate corresponding + // erratum stub. void - fix_errata(typename Sized_relobj_file::Views* pviews); + fix_errata_and_relocate_erratum_stubs( + typename Sized_relobj_file::Views* pviews); // Try to fix erratum 843419 in an optimized way. Return true if patch is // applied. bool try_fix_erratum_843419_optimized( - The_erratum_stub*, + The_erratum_stub*, AArch64_address, typename Sized_relobj_file::View_size&); // Whether a section needs to be scanned for relocation stubs. @@ -1939,15 +1982,17 @@ AArch64_relobj::do_count_local_symbols( } -// Fix all errata in the object. +// Fix all errata in the object and for each erratum, we relocate the +// corresponding erratum stub (by calling Stub_table::relocate_erratum_stub). template void -AArch64_relobj::fix_errata( +AArch64_relobj::fix_errata_and_relocate_erratum_stubs( typename Sized_relobj_file::Views* pviews) { typedef typename elfcpp::Swap<32,big_endian>::Valtype Insntype; unsigned int shnum = this->shnum(); + const Relobj::Output_sections& out_sections(this->output_sections()); for (unsigned int i = 1; i < shnum; ++i) { The_stub_table* stub_table = this->stub_table(i); @@ -1956,34 +2001,61 @@ AArch64_relobj::fix_errata( std::pair ipair(stub_table->find_erratum_stubs_for_input_section(this, i)); Erratum_stub_set_iter p = ipair.first, end = ipair.second; + typename Sized_relobj_file::View_size& + pview((*pviews)[i]); + AArch64_address view_offset = 0; + if (pview.is_input_output_view) + { + // In this case, write_sections has not added the output offset to + // the view's address, so we must do so. Currently this only happens + // for a relaxed section. + unsigned int index = this->adjust_shndx(i); + const Output_relaxed_input_section* poris = + out_sections[index]->find_relaxed_input_section(this, index); + gold_assert(poris != NULL); + view_offset = poris->address() - pview.address; + } + while (p != end) { The_erratum_stub* stub = *p; - typename Sized_relobj_file::View_size& - pview((*pviews)[i]); // Double check data before fix. - gold_assert(pview.address + stub->sh_offset() + gold_assert(pview.address + view_offset + stub->sh_offset() == stub->erratum_address()); // Update previously recorded erratum insn with relocated // version. Insntype* ip = - reinterpret_cast(pview.view + stub->sh_offset()); + reinterpret_cast( + pview.view + view_offset + stub->sh_offset()); Insntype insn_to_fix = ip[0]; stub->update_erratum_insn(insn_to_fix); // First try to see if erratum is 843419 and if it can be fixed // without using branch-to-stub. - if (!try_fix_erratum_843419_optimized(stub, pview)) + if (!try_fix_erratum_843419_optimized(stub, view_offset, pview)) { // Replace the erratum insn with a branch-to-stub. AArch64_address stub_address = stub_table->erratum_stub_address(stub); unsigned int b_offset = stub_address - stub->erratum_address(); AArch64_relocate_functions::construct_b( - pview.view + stub->sh_offset(), b_offset & 0xfffffff); + pview.view + view_offset + stub->sh_offset(), + b_offset & 0xfffffff); } + + // Erratum fix is done (or skipped), continue to relocate erratum + // stub. Note, when erratum fix is skipped (either because we + // proactively change the code sequence or the code sequence is + // changed by relaxation, etc), we can still safely relocate the + // erratum stub, ignoring the fact the erratum could never be + // executed. + stub_table->relocate_erratum_stub( + stub, + pview.view + (stub_table->address() - pview.address)); + + // Next erratum stub. ++p; } } @@ -1999,7 +2071,7 @@ AArch64_relobj::fix_errata( template bool AArch64_relobj::try_fix_erratum_843419_optimized( - The_erratum_stub* stub, + The_erratum_stub* stub, AArch64_address view_offset, typename Sized_relobj_file::View_size& pview) { if (stub->type() != ST_E_843419) @@ -2009,10 +2081,36 @@ AArch64_relobj::try_fix_erratum_843419_optimized( typedef typename elfcpp::Swap<32,big_endian>::Valtype Insntype; E843419_stub* e843419_stub = reinterpret_cast*>(stub); - AArch64_address pc = pview.address + e843419_stub->adrp_sh_offset(); - Insntype* adrp_view = reinterpret_cast( - pview.view + e843419_stub->adrp_sh_offset()); + AArch64_address pc = + pview.address + view_offset + e843419_stub->adrp_sh_offset(); + unsigned int adrp_offset = e843419_stub->adrp_sh_offset (); + Insntype* adrp_view = + reinterpret_cast(pview.view + view_offset + adrp_offset); Insntype adrp_insn = adrp_view[0]; + + // If the instruction at adrp_sh_offset is "mrs R, tpidr_el0", it may come + // from IE -> LE relaxation etc. This is a side-effect of TLS relaxation that + // ADRP has been turned into MRS, there is no erratum risk anymore. + // Therefore, we return true to avoid doing unnecessary branch-to-stub. + if (Insn_utilities::is_mrs_tpidr_el0(adrp_insn)) + return true; + + // If the instruction at adrp_sh_offset is not ADRP and the instruction before + // it is "mrs R, tpidr_el0", it may come from LD -> LE relaxation etc. + // Like the above case, there is no erratum risk any more, we can safely + // return true. + if (!Insn_utilities::is_adrp(adrp_insn) && adrp_offset) + { + Insntype* prev_view = + reinterpret_cast( + pview.view + view_offset + adrp_offset - 4); + Insntype prev_insn = prev_view[0]; + + if (Insn_utilities::is_mrs_tpidr_el0(prev_insn)) + return true; + } + + /* If we reach here, the first instruction must be ADRP. */ gold_assert(Insn_utilities::is_adrp(adrp_insn)); // Get adrp 33-bit signed imm value. int64_t adrp_imm = Insn_utilities:: @@ -2059,16 +2157,19 @@ AArch64_relobj::do_relocate_sections( if (parameters->options().relocatable()) return; + // This part only relocates erratum stubs that belong to input sections of this + // object file. if (parameters->options().fix_cortex_a53_843419() || parameters->options().fix_cortex_a53_835769()) - this->fix_errata(pviews); + this->fix_errata_and_relocate_erratum_stubs(pviews); Relocate_info relinfo; relinfo.symtab = symtab; relinfo.layout = layout; relinfo.object = this; - // Relocate stub tables. + // This part relocates all reloc stubs that are contained in stub_tables of + // this object file. unsigned int shnum = this->shnum(); The_target_aarch64* target = The_target_aarch64::current_target(); @@ -2097,8 +2198,8 @@ AArch64_relobj::do_relocate_sections( unsigned char* view = view_struct.view + offset; AArch64_address address = stub_table->address(); section_size_type view_size = stub_table->data_size(); - stub_table->relocate_stubs(&relinfo, target, os, view, address, - view_size); + stub_table->relocate_reloc_stubs(&relinfo, target, os, view, address, + view_size); } } } @@ -2215,6 +2316,19 @@ AArch64_relobj::scan_errata( output_address = poris->address(); } + // Update the addresses in previously generated erratum stubs. Unlike when + // we scan relocations for stubs, if section addresses have changed due to + // other relaxations we are unlikely to scan the same erratum instances + // again. + The_stub_table* stub_table = this->stub_table(shndx); + if (stub_table) + { + std::pair + ipair(stub_table->find_erratum_stubs_for_input_section(this, shndx)); + for (Erratum_stub_set_iter p = ipair.first; p != ipair.second; ++p) + (*p)->update_erratum_address(output_address); + } + section_size_type input_view_size = 0; const unsigned char* input_view = this->section_contents(shndx, &input_view_size, false); @@ -2989,11 +3103,11 @@ class Target_aarch64 : public Sized_target Address view_address, section_size_type); - // Relocate a single stub. + // Relocate a single reloc stub. void - relocate_stub(The_reloc_stub*, const Relocate_info*, - Output_section*, unsigned char*, Address, - section_size_type); + relocate_reloc_stub(The_reloc_stub*, const Relocate_info*, + Output_section*, unsigned char*, Address, + section_size_type); // Get the default AArch64 target. static This* @@ -3434,7 +3548,7 @@ const Target::Target_info Target_aarch64<64, false>::aarch64_info = false, // has_make_symbol false, // has_resolve false, // has_code_fill - true, // is_default_stack_executable + false, // is_default_stack_executable true, // can_icf_inline_merge_sections '\0', // wrap_char "/lib/ld.so.1", // program interpreter @@ -3451,6 +3565,7 @@ const Target::Target_info Target_aarch64<64, false>::aarch64_info = NULL, // attributes_vendor "_start", // entry_symbol_name 32, // hash_entry_size + elfcpp::SHT_PROGBITS, // unwind_section_type }; template<> @@ -3462,7 +3577,7 @@ const Target::Target_info Target_aarch64<32, false>::aarch64_info = false, // has_make_symbol false, // has_resolve false, // has_code_fill - true, // is_default_stack_executable + false, // is_default_stack_executable false, // can_icf_inline_merge_sections '\0', // wrap_char "/lib/ld.so.1", // program interpreter @@ -3479,6 +3594,7 @@ const Target::Target_info Target_aarch64<32, false>::aarch64_info = NULL, // attributes_vendor "_start", // entry_symbol_name 32, // hash_entry_size + elfcpp::SHT_PROGBITS, // unwind_section_type }; template<> @@ -3490,7 +3606,7 @@ const Target::Target_info Target_aarch64<64, true>::aarch64_info = false, // has_make_symbol false, // has_resolve false, // has_code_fill - true, // is_default_stack_executable + false, // is_default_stack_executable true, // can_icf_inline_merge_sections '\0', // wrap_char "/lib/ld.so.1", // program interpreter @@ -3507,6 +3623,7 @@ const Target::Target_info Target_aarch64<64, true>::aarch64_info = NULL, // attributes_vendor "_start", // entry_symbol_name 32, // hash_entry_size + elfcpp::SHT_PROGBITS, // unwind_section_type }; template<> @@ -3518,7 +3635,7 @@ const Target::Target_info Target_aarch64<32, true>::aarch64_info = false, // has_make_symbol false, // has_resolve false, // has_code_fill - true, // is_default_stack_executable + false, // is_default_stack_executable false, // can_icf_inline_merge_sections '\0', // wrap_char "/lib/ld.so.1", // program interpreter @@ -3535,6 +3652,7 @@ const Target::Target_info Target_aarch64<32, true>::aarch64_info = NULL, // attributes_vendor "_start", // entry_symbol_name 32, // hash_entry_size + elfcpp::SHT_PROGBITS, // unwind_section_type }; // Get the GOT section, creating it if necessary. @@ -3741,13 +3859,18 @@ Target_aarch64::scan_reloc_for_stub( if (gsym->use_plt_offset(arp->reference_flags())) { // This uses a PLT, change the symbol value. - symval.set_output_value(this->plt_section()->address() - + gsym->plt_offset()); + symval.set_output_value(this->plt_address_for_global(gsym)); psymval = &symval; } else if (gsym->is_undefined()) - // There is no need to generate a stub symbol is undefined. - return; + { + // There is no need to generate a stub symbol if the original symbol + // is undefined. + gold_debug(DEBUG_TARGET, + "stub: not creating a stub for undefined symbol %s in file %s", + gsym->name(), aarch64_relobj->name().c_str()); + return; + } } // Get the symbol value. @@ -3849,6 +3972,7 @@ Target_aarch64::scan_reloc_section_for_stubs( const Symbol_value *psymval; bool is_defined_in_discarded_section; unsigned int shndx; + const Symbol* gsym = NULL; if (r_sym < local_count) { sym = NULL; @@ -3901,7 +4025,6 @@ Target_aarch64::scan_reloc_section_for_stubs( } else { - const Symbol* gsym; gsym = object->global_symbol(r_sym); gold_assert(gsym != NULL); if (gsym->is_forwarder()) @@ -3942,16 +4065,16 @@ Target_aarch64::scan_reloc_section_for_stubs( Symbol_value symval2; if (is_defined_in_discarded_section) { + std::string name = object->section_name(relinfo->data_shndx); + if (comdat_behavior == CB_UNDETERMINED) - { - std::string name = object->section_name(relinfo->data_shndx); comdat_behavior = default_comdat_behavior.get(name.c_str()); - } + if (comdat_behavior == CB_PRETEND) { bool found; typename elfcpp::Elf_types::Elf_Addr value = - object->map_to_kept_section(shndx, &found); + object->map_to_kept_section(shndx, name, &found); if (found) symval2.set_output_value(value + psymval->input_value()); else @@ -3959,21 +4082,14 @@ Target_aarch64::scan_reloc_section_for_stubs( } else { - if (comdat_behavior == CB_WARNING) - gold_warning_at_location(relinfo, i, offset, - _("relocation refers to discarded " - "section")); + if (comdat_behavior == CB_ERROR) + issue_discarded_error(relinfo, i, offset, r_sym, gsym); symval2.set_output_value(0); } symval2.set_no_output_symtab_entry(); psymval = &symval2; } - // If symbol is a section symbol, we don't know the actual type of - // destination. Give up. - if (psymval->is_section_symbol()) - continue; - this->scan_reloc_for_stub(relinfo, r_type, sym, r_sym, psymval, addend, view_address + offset); } // End of iterating relocs in a section @@ -4008,16 +4124,16 @@ Target_aarch64::scan_section_for_stubs( } -// Relocate a single stub. +// Relocate a single reloc stub. template void Target_aarch64:: -relocate_stub(The_reloc_stub* stub, - const The_relocate_info*, - Output_section*, - unsigned char* view, - Address address, - section_size_type) +relocate_reloc_stub(The_reloc_stub* stub, + const The_relocate_info*, + Output_section*, + unsigned char* view, + Address address, + section_size_type) { typedef AArch64_relocate_functions The_reloc_functions; typedef typename The_reloc_functions::Status The_reloc_functions_status; @@ -5405,6 +5521,21 @@ maybe_apply_stub(unsigned int r_type, const The_aarch64_relobj* aarch64_relobj = static_cast(object); + const AArch64_reloc_property* arp = + aarch64_reloc_property_table->get_reloc_property(r_type); + gold_assert(arp != NULL); + + // We don't create stubs for undefined symbols, but do for weak. + if (gsym + && !gsym->use_plt_offset(arp->reference_flags()) + && gsym->is_undefined()) + { + gold_debug(DEBUG_TARGET, + "stub: looking for a stub for undefined symbol %s in file %s", + gsym->name(), aarch64_relobj->name().c_str()); + return false; + } + The_stub_table* stub_table = aarch64_relobj->stub_table(relinfo->data_shndx); gold_assert(stub_table != NULL); @@ -5416,9 +5547,6 @@ maybe_apply_stub(unsigned int r_type, Address new_branch_target = stub_table->address() + stub->offset(); typename elfcpp::Swap::Valtype branch_offset = new_branch_target - address; - const AArch64_reloc_property* arp = - aarch64_reloc_property_table->get_reloc_property(r_type); - gold_assert(arp != NULL); typename This::Status status = This::template rela_general<32>(view, branch_offset, 0, arp); if (status != This::STATUS_OKAY) @@ -5790,6 +5918,14 @@ Target_aarch64::optimize_tls_reloc(bool is_final, case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_HI12: case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12: case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: + case elfcpp::R_AARCH64_TLSLE_LDST8_TPREL_LO12: + case elfcpp::R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC: + case elfcpp::R_AARCH64_TLSLE_LDST16_TPREL_LO12: + case elfcpp::R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC: + case elfcpp::R_AARCH64_TLSLE_LDST32_TPREL_LO12: + case elfcpp::R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC: + case elfcpp::R_AARCH64_TLSLE_LDST64_TPREL_LO12: + case elfcpp::R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: // When we already have Local-Exec, there is nothing further we // can do. return tls::TLSOPT_NONE; @@ -6136,6 +6272,14 @@ Target_aarch64::Scan::local( case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_HI12: case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12: case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: + case elfcpp::R_AARCH64_TLSLE_LDST8_TPREL_LO12: + case elfcpp::R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC: + case elfcpp::R_AARCH64_TLSLE_LDST16_TPREL_LO12: + case elfcpp::R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC: + case elfcpp::R_AARCH64_TLSLE_LDST32_TPREL_LO12: + case elfcpp::R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC: + case elfcpp::R_AARCH64_TLSLE_LDST64_TPREL_LO12: + case elfcpp::R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: { layout->set_has_static_tls(); bool output_is_shared = parameters->options().shared(); @@ -6352,6 +6496,17 @@ Target_aarch64::Scan::global( gold_error(_("%s: unsupported reloc %u in pos independent link."), object->name().c_str(), r_type); } + // Make a PLT entry if necessary. + if (gsym->needs_plt_entry()) + { + target->make_plt_entry(symtab, layout, gsym); + // Since this is not a PC-relative relocation, we may be + // taking the address of a function. In that case we need to + // set the entry in the dynamic symbol table to the address of + // the PLT entry. + if (gsym->is_from_dynobj() && !parameters->options().shared()) + gsym->set_needs_dynsym_value(); + } break; case elfcpp::R_AARCH64_LD_PREL_LO19: // 273 @@ -6553,7 +6708,15 @@ Target_aarch64::Scan::global( case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC: case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_HI12: case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12: - case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: // Local executable + case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: + case elfcpp::R_AARCH64_TLSLE_LDST8_TPREL_LO12: + case elfcpp::R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC: + case elfcpp::R_AARCH64_TLSLE_LDST16_TPREL_LO12: + case elfcpp::R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC: + case elfcpp::R_AARCH64_TLSLE_LDST32_TPREL_LO12: + case elfcpp::R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC: + case elfcpp::R_AARCH64_TLSLE_LDST64_TPREL_LO12: + case elfcpp::R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: // Local executable layout->set_has_static_tls(); if (parameters->options().shared()) gold_error(_("%s: unsupported TLSLE reloc type %u in shared objects."), @@ -6813,11 +6976,11 @@ Target_aarch64::do_finalize_sections( } // Set the size of the _GLOBAL_OFFSET_TABLE_ symbol to the size of - // the .got.plt section. + // the .got section. Symbol* sym = this->global_offset_table_; if (sym != NULL) { - uint64_t data_size = this->got_plt_->current_data_size(); + uint64_t data_size = this->got_->current_data_size(); symtab->get_sized_symbol(sym)->set_symsize(data_size); // If the .got section is more than 0x8000 bytes, we add @@ -7150,6 +7313,14 @@ Target_aarch64::Relocate::relocate( case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_HI12: case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12: case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: + case elfcpp::R_AARCH64_TLSLE_LDST8_TPREL_LO12: + case elfcpp::R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC: + case elfcpp::R_AARCH64_TLSLE_LDST16_TPREL_LO12: + case elfcpp::R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC: + case elfcpp::R_AARCH64_TLSLE_LDST32_TPREL_LO12: + case elfcpp::R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC: + case elfcpp::R_AARCH64_TLSLE_LDST64_TPREL_LO12: + case elfcpp::R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: case elfcpp::R_AARCH64_TLSDESC_ADR_PAGE21: case elfcpp::R_AARCH64_TLSDESC_LD64_LO12: case elfcpp::R_AARCH64_TLSDESC_ADD_LO12: @@ -7429,6 +7600,14 @@ Target_aarch64::Relocate::relocate_tls( case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_HI12: case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12: case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: + case elfcpp::R_AARCH64_TLSLE_LDST8_TPREL_LO12: + case elfcpp::R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC: + case elfcpp::R_AARCH64_TLSLE_LDST16_TPREL_LO12: + case elfcpp::R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC: + case elfcpp::R_AARCH64_TLSLE_LDST32_TPREL_LO12: + case elfcpp::R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC: + case elfcpp::R_AARCH64_TLSLE_LDST64_TPREL_LO12: + case elfcpp::R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: { gold_assert(tls_segment != NULL); AArch64_address value = psymval->value(object, 0); @@ -7482,15 +7661,15 @@ Target_aarch64::Relocate::relocate_tls( tls_got_offset_type = (tlsopt == tls::TLSOPT_TO_IE ? GOT_TYPE_TLS_OFFSET : GOT_TYPE_TLS_DESC); - unsigned int got_tlsdesc_offset = 0; + int got_tlsdesc_offset = 0; if (r_type != elfcpp::R_AARCH64_TLSDESC_CALL && tlsopt == tls::TLSOPT_NONE) { // We created GOT entries in the .got.tlsdesc portion of the // .got.plt section, but the offset stored in the symbol is the // offset within .got.tlsdesc. - got_tlsdesc_offset = (target->got_->data_size() - + target->got_plt_section()->data_size()); + got_tlsdesc_offset = (target->got_tlsdesc_->address() + - target->got_->address()); } typename elfcpp::Elf_types::Elf_Addr got_entry_address; if (gsym != NULL) @@ -7695,8 +7874,8 @@ Target_aarch64::Relocate::tls_ld_to_le( { // Ideally we should give up gd_to_le relaxation and do gd access. // However the gd_to_le relaxation decision has been made early - // in the scan stage, where we did not allocate any GOT entry for - // this symbol. Therefore we have to exit and report error now. + // in the scan stage, where we did not allocate a GOT entry for + // this symbol. Therefore we have to exit and report an error now. gold_error(_("unexpected reloc insn sequence while relaxing " "tls gd to le for reloc %u."), r_type); return aarch64_reloc_funcs::STATUS_BAD_RELOC;