diff options
Diffstat (limited to 'gold/aarch64.cc')
-rw-r--r-- | gold/aarch64.cc | 284 |
1 files changed, 173 insertions, 111 deletions
diff --git a/gold/aarch64.cc b/gold/aarch64.cc index 11bb48e..4c6e920 100644 --- a/gold/aarch64.cc +++ b/gold/aarch64.cc @@ -270,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; @@ -1049,6 +1049,17 @@ public: return this->sh_offset_ < k.sh_offset_; } + void + invalidate_erratum_stub() + { + gold_assert(this->relobj_ != NULL); + this->relobj_ = NULL; + } + + bool + is_invalidated_erratum_stub() + { return this->relobj_ == NULL; } + protected: virtual void do_write(unsigned char*, section_size_type); @@ -1090,7 +1101,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_; }; @@ -1346,7 +1357,8 @@ Reloc_stub<size, big_endian>::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<int size, bool big_endian> class Stub_table : public Output_data @@ -1438,14 +1450,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. @@ -1485,15 +1501,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. @@ -1593,76 +1609,85 @@ Stub_table<size, big_endian>::add_reloc_stub( } -// Relocate all stubs in this stub table. +// Relocate an erratum stub. template<int size, bool big_endian> void Stub_table<size, big_endian>:: -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<section_size_type>(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<big_endian>::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<size, big_endian>::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<size, big_endian>::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<int size, bool big_endian> void Stub_table<size, big_endian>:: -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<section_size_type>(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<int size, bool big_endian> +void +Stub_table<size, big_endian>:: +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(); @@ -1670,8 +1695,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); } @@ -1829,15 +1854,17 @@ class AArch64_relobj : public Sized_relobj_file<size, big_endian> Stringpool_template<char>*); 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<size, big_endian>::Views* pviews); + fix_errata_and_relocate_erratum_stubs( + typename Sized_relobj_file<size, big_endian>::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<size, big_endian>::View_size&); // Whether a section needs to be scanned for relocation stubs. @@ -1943,15 +1970,17 @@ AArch64_relobj<size, big_endian>::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<int size, bool big_endian> void -AArch64_relobj<size, big_endian>::fix_errata( +AArch64_relobj<size, big_endian>::fix_errata_and_relocate_erratum_stubs( typename Sized_relobj_file<size, big_endian>::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); @@ -1960,34 +1989,61 @@ AArch64_relobj<size, big_endian>::fix_errata( std::pair<Erratum_stub_set_iter, Erratum_stub_set_iter> 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<size, big_endian>::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<size, big_endian>::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<Insntype*>(pview.view + stub->sh_offset()); + reinterpret_cast<Insntype*>( + 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<size, big_endian>::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 + view_offset + (stub_table->address() - pview.address)); + + // Next erratum stub. ++p; } } @@ -2003,7 +2059,7 @@ AArch64_relobj<size, big_endian>::fix_errata( template<int size, bool big_endian> bool AArch64_relobj<size, big_endian>::try_fix_erratum_843419_optimized( - The_erratum_stub* stub, + The_erratum_stub* stub, AArch64_address view_offset, typename Sized_relobj_file<size, big_endian>::View_size& pview) { if (stub->type() != ST_E_843419) @@ -2013,9 +2069,11 @@ AArch64_relobj<size, big_endian>::try_fix_erratum_843419_optimized( typedef typename elfcpp::Swap<32,big_endian>::Valtype Insntype; E843419_stub<size, big_endian>* e843419_stub = reinterpret_cast<E843419_stub<size, big_endian>*>(stub); - AArch64_address pc = pview.address + 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<Insntype*>(pview.view + adrp_offset); + Insntype* adrp_view = + reinterpret_cast<Insntype*>(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 @@ -2031,8 +2089,9 @@ AArch64_relobj<size, big_endian>::try_fix_erratum_843419_optimized( // return true. if (!Insn_utilities::is_adrp(adrp_insn) && adrp_offset) { - Insntype* prev_view - = reinterpret_cast<Insntype*>(pview.view + adrp_offset - 4); + Insntype* prev_view = + reinterpret_cast<Insntype*>( + pview.view + view_offset + adrp_offset - 4); Insntype prev_insn = prev_view[0]; if (Insn_utilities::is_mrs_tpidr_el0(prev_insn)) @@ -2086,16 +2145,19 @@ AArch64_relobj<size, big_endian>::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<size, big_endian> 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(); @@ -2124,8 +2186,8 @@ AArch64_relobj<size, big_endian>::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); } } } @@ -3016,11 +3078,11 @@ class Target_aarch64 : public Sized_target<size, big_endian> Address view_address, section_size_type); - // Relocate a single stub. + // Relocate a single reloc stub. void - relocate_stub(The_reloc_stub*, const Relocate_info<size, big_endian>*, - Output_section*, unsigned char*, Address, - section_size_type); + relocate_reloc_stub(The_reloc_stub*, const Relocate_info<size, big_endian>*, + Output_section*, unsigned char*, Address, + section_size_type); // Get the default AArch64 target. static This* @@ -3461,7 +3523,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 @@ -3489,7 +3551,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 @@ -3517,7 +3579,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 @@ -3545,7 +3607,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 @@ -4035,16 +4097,16 @@ Target_aarch64<size, big_endian>::scan_section_for_stubs( } -// Relocate a single stub. +// Relocate a single reloc stub. template<int size, bool big_endian> void Target_aarch64<size, big_endian>:: -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<size, big_endian> The_reloc_functions; typedef typename The_reloc_functions::Status The_reloc_functions_status; @@ -7521,15 +7583,15 @@ Target_aarch64<size, big_endian>::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<size>::Elf_Addr got_entry_address; if (gsym != NULL) |