diff options
Diffstat (limited to 'gold')
-rw-r--r-- | gold/aarch64.cc | 222 |
1 files changed, 132 insertions, 90 deletions
diff --git a/gold/aarch64.cc b/gold/aarch64.cc index 11bb48e..696df19 100644 --- a/gold/aarch64.cc +++ b/gold/aarch64.cc @@ -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); @@ -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,9 +1854,11 @@ 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. @@ -1943,11 +1970,12 @@ 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; @@ -1988,6 +2016,17 @@ AArch64_relobj<size, big_endian>::fix_errata( AArch64_relocate_functions<size, big_endian>::construct_b( pview.view + 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; } } @@ -2086,16 +2125,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 +2166,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 +3058,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* @@ -4035,16 +4077,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; |