X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Faarch64.cc;h=07abe44931f34504a986bf30500f0a862b2a9570;hb=37ab86550b9da31d6c32c2d3384bd27f0426e935;hp=7a3fe3bd806cc13ac891d59ba24dda7f18dcf3cb;hpb=9363c7c3ad54a5f92d74ec8e48eda570de229f63;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/aarch64.cc b/gold/aarch64.cc index 7a3fe3bd80..07abe44931 100644 --- a/gold/aarch64.cc +++ b/gold/aarch64.cc @@ -1,6 +1,6 @@ // aarch64.cc -- aarch64 target support for gold. -// Copyright (C) 2014 Free Software Foundation, Inc. +// Copyright (C) 2014-2020 Free Software Foundation, Inc. // Written by Jing Yu and Han Shen . // This file is part of gold. @@ -23,6 +23,8 @@ #include "gold.h" #include +#include +#include #include "elfcpp.h" #include "dwarf.h" @@ -47,6 +49,7 @@ // The first three .got.plt entries are reserved. const int32_t AARCH64_GOTPLT_RESERVE_COUNT = 3; + namespace { @@ -64,6 +67,363 @@ class Target_aarch64; template class AArch64_relocate_functions; +// Utility class dealing with insns. This is ported from macros in +// bfd/elfnn-aarch64.cc, but wrapped inside a class as static members. This +// class is used in erratum sequence scanning. + +template +class AArch64_insn_utilities +{ +public: + typedef typename elfcpp::Swap<32, big_endian>::Valtype Insntype; + + static const int BYTES_PER_INSN; + + // Zero register encoding - 31. + static const unsigned int AARCH64_ZR; + + static unsigned int + aarch64_bit(Insntype insn, int pos) + { return ((1 << pos) & insn) >> pos; } + + static unsigned int + aarch64_bits(Insntype insn, int pos, int l) + { return (insn >> pos) & ((1 << l) - 1); } + + // Get the encoding field "op31" of 3-source data processing insns. "op31" is + // the name defined in armv8 insn manual C3.5.9. + static unsigned int + aarch64_op31(Insntype insn) + { return aarch64_bits(insn, 21, 3); } + + // Get the encoding field "ra" of 3-source data processing insns. "ra" is the + // third source register. See armv8 insn manual C3.5.9. + static unsigned int + aarch64_ra(Insntype insn) + { return aarch64_bits(insn, 10, 5); } + + static bool + is_adr(const Insntype insn) + { return (insn & 0x9F000000) == 0x10000000; } + + static bool + 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); } + + static unsigned int + aarch64_rn(const Insntype insn) + { return aarch64_bits(insn, 5, 5); } + + static unsigned int + aarch64_rd(const Insntype insn) + { return aarch64_bits(insn, 0, 5); } + + static unsigned int + aarch64_rt(const Insntype insn) + { return aarch64_bits(insn, 0, 5); } + + static unsigned int + aarch64_rt2(const Insntype insn) + { return aarch64_bits(insn, 10, 5); } + + // Encode imm21 into adr. Signed imm21 is in the range of [-1M, 1M). + static Insntype + aarch64_adr_encode_imm(Insntype adr, int imm21) + { + gold_assert(is_adr(adr)); + gold_assert(-(1 << 20) <= imm21 && imm21 < (1 << 20)); + const int mask19 = (1 << 19) - 1; + const int mask2 = 3; + adr &= ~((mask19 << 5) | (mask2 << 29)); + adr |= ((imm21 & mask2) << 29) | (((imm21 >> 2) & mask19) << 5); + return adr; + } + + // Retrieve encoded adrp 33-bit signed imm value. This value is obtained by + // 21-bit signed imm encoded in the insn multiplied by 4k (page size) and + // 64-bit sign-extended, resulting in [-4G, 4G) with 12-lsb being 0. + static int64_t + aarch64_adrp_decode_imm(const Insntype adrp) + { + const int mask19 = (1 << 19) - 1; + const int mask2 = 3; + gold_assert(is_adrp(adrp)); + // 21-bit imm encoded in adrp. + uint64_t imm = ((adrp >> 29) & mask2) | (((adrp >> 5) & mask19) << 2); + // Retrieve msb of 21-bit-signed imm for sign extension. + uint64_t msbt = (imm >> 20) & 1; + // Real value is imm multiplied by 4k. Value now has 33-bit information. + int64_t value = imm << 12; + // Sign extend to 64-bit by repeating msbt 31 (64-33) times and merge it + // with value. + return ((((uint64_t)(1) << 32) - msbt) << 33) | value; + } + + static bool + aarch64_b(const Insntype insn) + { return (insn & 0xFC000000) == 0x14000000; } + + static bool + aarch64_bl(const Insntype insn) + { return (insn & 0xFC000000) == 0x94000000; } + + static bool + aarch64_blr(const Insntype insn) + { return (insn & 0xFFFFFC1F) == 0xD63F0000; } + + static bool + aarch64_br(const Insntype insn) + { return (insn & 0xFFFFFC1F) == 0xD61F0000; } + + // All ld/st ops. See C4-182 of the ARM ARM. The encoding space for + // LD_PCREL, LDST_RO, LDST_UI and LDST_UIMM cover prefetch ops. + static bool + aarch64_ld(Insntype insn) { return aarch64_bit(insn, 22) == 1; } + + static bool + aarch64_ldst(Insntype insn) + { return (insn & 0x0a000000) == 0x08000000; } + + static bool + aarch64_ldst_ex(Insntype insn) + { return (insn & 0x3f000000) == 0x08000000; } + + static bool + aarch64_ldst_pcrel(Insntype insn) + { return (insn & 0x3b000000) == 0x18000000; } + + static bool + aarch64_ldst_nap(Insntype insn) + { return (insn & 0x3b800000) == 0x28000000; } + + static bool + aarch64_ldstp_pi(Insntype insn) + { return (insn & 0x3b800000) == 0x28800000; } + + static bool + aarch64_ldstp_o(Insntype insn) + { return (insn & 0x3b800000) == 0x29000000; } + + static bool + aarch64_ldstp_pre(Insntype insn) + { return (insn & 0x3b800000) == 0x29800000; } + + static bool + aarch64_ldst_ui(Insntype insn) + { return (insn & 0x3b200c00) == 0x38000000; } + + static bool + aarch64_ldst_piimm(Insntype insn) + { return (insn & 0x3b200c00) == 0x38000400; } + + static bool + aarch64_ldst_u(Insntype insn) + { return (insn & 0x3b200c00) == 0x38000800; } + + static bool + aarch64_ldst_preimm(Insntype insn) + { return (insn & 0x3b200c00) == 0x38000c00; } + + static bool + aarch64_ldst_ro(Insntype insn) + { return (insn & 0x3b200c00) == 0x38200800; } + + static bool + aarch64_ldst_uimm(Insntype insn) + { return (insn & 0x3b000000) == 0x39000000; } + + static bool + aarch64_ldst_simd_m(Insntype insn) + { return (insn & 0xbfbf0000) == 0x0c000000; } + + static bool + aarch64_ldst_simd_m_pi(Insntype insn) + { return (insn & 0xbfa00000) == 0x0c800000; } + + static bool + aarch64_ldst_simd_s(Insntype insn) + { return (insn & 0xbf9f0000) == 0x0d000000; } + + static bool + aarch64_ldst_simd_s_pi(Insntype insn) + { return (insn & 0xbf800000) == 0x0d800000; } + + // Classify an INSN if it is indeed a load/store. Return true if INSN is a + // LD/ST instruction otherwise return false. For scalar LD/ST instructions + // PAIR is FALSE, RT is returned and RT2 is set equal to RT. For LD/ST pair + // instructions PAIR is TRUE, RT and RT2 are returned. + static bool + aarch64_mem_op_p(Insntype insn, unsigned int *rt, unsigned int *rt2, + bool *pair, bool *load) + { + uint32_t opcode; + unsigned int r; + uint32_t opc = 0; + uint32_t v = 0; + uint32_t opc_v = 0; + + /* Bail out quickly if INSN doesn't fall into the load-store + encoding space. */ + if (!aarch64_ldst (insn)) + return false; + + *pair = false; + *load = false; + if (aarch64_ldst_ex (insn)) + { + *rt = aarch64_rt (insn); + *rt2 = *rt; + if (aarch64_bit (insn, 21) == 1) + { + *pair = true; + *rt2 = aarch64_rt2 (insn); + } + *load = aarch64_ld (insn); + return true; + } + else if (aarch64_ldst_nap (insn) + || aarch64_ldstp_pi (insn) + || aarch64_ldstp_o (insn) + || aarch64_ldstp_pre (insn)) + { + *pair = true; + *rt = aarch64_rt (insn); + *rt2 = aarch64_rt2 (insn); + *load = aarch64_ld (insn); + return true; + } + else if (aarch64_ldst_pcrel (insn) + || aarch64_ldst_ui (insn) + || aarch64_ldst_piimm (insn) + || aarch64_ldst_u (insn) + || aarch64_ldst_preimm (insn) + || aarch64_ldst_ro (insn) + || aarch64_ldst_uimm (insn)) + { + *rt = aarch64_rt (insn); + *rt2 = *rt; + if (aarch64_ldst_pcrel (insn)) + *load = true; + opc = aarch64_bits (insn, 22, 2); + v = aarch64_bit (insn, 26); + opc_v = opc | (v << 2); + *load = (opc_v == 1 || opc_v == 2 || opc_v == 3 + || opc_v == 5 || opc_v == 7); + return true; + } + else if (aarch64_ldst_simd_m (insn) + || aarch64_ldst_simd_m_pi (insn)) + { + *rt = aarch64_rt (insn); + *load = aarch64_bit (insn, 22); + opcode = (insn >> 12) & 0xf; + switch (opcode) + { + case 0: + case 2: + *rt2 = *rt + 3; + break; + + case 4: + case 6: + *rt2 = *rt + 2; + break; + + case 7: + *rt2 = *rt; + break; + + case 8: + case 10: + *rt2 = *rt + 1; + break; + + default: + return false; + } + return true; + } + else if (aarch64_ldst_simd_s (insn) + || aarch64_ldst_simd_s_pi (insn)) + { + *rt = aarch64_rt (insn); + r = (insn >> 21) & 1; + *load = aarch64_bit (insn, 22); + opcode = (insn >> 13) & 0x7; + switch (opcode) + { + case 0: + case 2: + case 4: + *rt2 = *rt + r; + break; + + case 1: + case 3: + case 5: + *rt2 = *rt + (r == 0 ? 2 : 3); + break; + + case 6: + *rt2 = *rt + r; + break; + + case 7: + *rt2 = *rt + (r == 0 ? 2 : 3); + break; + + default: + return false; + } + return true; + } + return false; + } // End of "aarch64_mem_op_p". + + // Return true if INSN is mac insn. + static bool + aarch64_mac(Insntype insn) + { return (insn & 0xff000000) == 0x9b000000; } + + // Return true if INSN is multiply-accumulate. + // (This is similar to implementaton in elfnn-aarch64.c.) + static bool + aarch64_mlxl(Insntype insn) + { + uint32_t op31 = aarch64_op31(insn); + if (aarch64_mac(insn) + && (op31 == 0 || op31 == 1 || op31 == 5) + /* Exclude MUL instructions which are encoded as a multiple-accumulate + with RA = XZR. */ + && aarch64_ra(insn) != AARCH64_ZR) + { + return true; + } + return false; + } +}; // End of "AArch64_insn_utilities". + + +// Insn length in byte. + +template +const int AArch64_insn_utilities::BYTES_PER_INSN = 4; + + +// Zero register encoding - 31. + +template +const unsigned int AArch64_insn_utilities::AARCH64_ZR = 0x1f; + + // Output_data_got_aarch64 class. template @@ -76,6 +436,27 @@ class Output_data_got_aarch64 : public Output_data_got symbol_table_(symtab), layout_(layout) { } + // Add a static entry for the GOT entry at OFFSET. GSYM is a global + // symbol and R_TYPE is the code of a dynamic relocation that needs to be + // applied in a static link. + void + add_static_reloc(unsigned int got_offset, unsigned int r_type, Symbol* gsym) + { this->static_relocs_.push_back(Static_reloc(got_offset, r_type, gsym)); } + + + // Add a static reloc for the GOT entry at OFFSET. RELOBJ is an object + // defining a local symbol with INDEX. R_TYPE is the code of a dynamic + // relocation that needs to be applied in a static link. + void + add_static_reloc(unsigned int got_offset, unsigned int r_type, + Sized_relobj_file* relobj, + unsigned int index) + { + this->static_relocs_.push_back(Static_reloc(got_offset, r_type, relobj, + index)); + } + + protected: // Write out the GOT table. void @@ -86,6 +467,104 @@ class Output_data_got_aarch64 : public Output_data_got Valtype dynamic_addr = dynamic == NULL ? 0 : dynamic->address(); this->replace_constant(0, dynamic_addr); Output_data_got::do_write(of); + + // Handling static relocs + if (this->static_relocs_.empty()) + return; + + typedef typename elfcpp::Elf_types::Elf_Addr AArch64_address; + + gold_assert(parameters->doing_static_link()); + const off_t offset = this->offset(); + const section_size_type oview_size = + convert_to_section_size_type(this->data_size()); + unsigned char* const oview = of->get_output_view(offset, oview_size); + + Output_segment* tls_segment = this->layout_->tls_segment(); + gold_assert(tls_segment != NULL); + + AArch64_address aligned_tcb_address = + align_address(Target_aarch64::TCB_SIZE, + tls_segment->maximum_alignment()); + + for (size_t i = 0; i < this->static_relocs_.size(); ++i) + { + Static_reloc& reloc(this->static_relocs_[i]); + AArch64_address value; + + if (!reloc.symbol_is_global()) + { + Sized_relobj_file* object = reloc.relobj(); + const Symbol_value* psymval = + reloc.relobj()->local_symbol(reloc.index()); + + // We are doing static linking. Issue an error and skip this + // relocation if the symbol is undefined or in a discarded_section. + bool is_ordinary; + unsigned int shndx = psymval->input_shndx(&is_ordinary); + if ((shndx == elfcpp::SHN_UNDEF) + || (is_ordinary + && shndx != elfcpp::SHN_UNDEF + && !object->is_section_included(shndx) + && !this->symbol_table_->is_section_folded(object, shndx))) + { + gold_error(_("undefined or discarded local symbol %u from " + " object %s in GOT"), + reloc.index(), reloc.relobj()->name().c_str()); + continue; + } + value = psymval->value(object, 0); + } + else + { + const Symbol* gsym = reloc.symbol(); + gold_assert(gsym != NULL); + if (gsym->is_forwarder()) + gsym = this->symbol_table_->resolve_forwards(gsym); + + // We are doing static linking. Issue an error and skip this + // relocation if the symbol is undefined or in a discarded_section + // unless it is a weakly_undefined symbol. + if ((gsym->is_defined_in_discarded_section() + || gsym->is_undefined()) + && !gsym->is_weak_undefined()) + { + gold_error(_("undefined or discarded symbol %s in GOT"), + gsym->name()); + continue; + } + + if (!gsym->is_weak_undefined()) + { + const Sized_symbol* sym = + static_cast*>(gsym); + value = sym->value(); + } + else + value = 0; + } + + unsigned got_offset = reloc.got_offset(); + gold_assert(got_offset < oview_size); + + typedef typename elfcpp::Swap::Valtype Valtype; + Valtype* wv = reinterpret_cast(oview + got_offset); + Valtype x; + switch (reloc.r_type()) + { + case elfcpp::R_AARCH64_TLS_DTPREL64: + x = value; + break; + case elfcpp::R_AARCH64_TLS_TPREL64: + x = value + aligned_tcb_address; + break; + default: + gold_unreachable(); + } + elfcpp::Swap::writeval(wv, x); + } + + of->write_output_view(offset, oview_size, oview); } private: @@ -94,1427 +573,5397 @@ class Output_data_got_aarch64 : public Output_data_got // A pointer to the Layout class, so that we can find the .dynamic // section when we write out the GOT section. Layout* layout_; -}; -AArch64_reloc_property_table* aarch64_reloc_property_table = NULL; + // This class represent dynamic relocations that need to be applied by + // gold because we are using TLS relocations in a static link. + class Static_reloc + { + public: + Static_reloc(unsigned int got_offset, unsigned int r_type, Symbol* gsym) + : got_offset_(got_offset), r_type_(r_type), symbol_is_global_(true) + { this->u_.global.symbol = gsym; } + + Static_reloc(unsigned int got_offset, unsigned int r_type, + Sized_relobj_file* relobj, unsigned int index) + : got_offset_(got_offset), r_type_(r_type), symbol_is_global_(false) + { + this->u_.local.relobj = relobj; + this->u_.local.index = index; + } + + // Return the GOT offset. + unsigned int + got_offset() const + { return this->got_offset_; } + + // Relocation type. + unsigned int + r_type() const + { return this->r_type_; } + + // Whether the symbol is global or not. + bool + symbol_is_global() const + { return this->symbol_is_global_; } + + // For a relocation against a global symbol, the global symbol. + Symbol* + symbol() const + { + gold_assert(this->symbol_is_global_); + return this->u_.global.symbol; + } + + // For a relocation against a local symbol, the defining object. + Sized_relobj_file* + relobj() const + { + gold_assert(!this->symbol_is_global_); + return this->u_.local.relobj; + } + + // For a relocation against a local symbol, the local symbol index. + unsigned int + index() const + { + gold_assert(!this->symbol_is_global_); + return this->u_.local.index; + } + + private: + // GOT offset of the entry to which this relocation is applied. + unsigned int got_offset_; + // Type of relocation. + unsigned int r_type_; + // Whether this relocation is against a global symbol. + bool symbol_is_global_; + // A global or local symbol. + union + { + struct + { + // For a global symbol, the symbol itself. + Symbol* symbol; + } global; + struct + { + // For a local symbol, the object defining the symbol. + Sized_relobj_file* relobj; + // For a local symbol, the symbol index. + unsigned int index; + } local; + } u_; + }; // End of inner class Static_reloc + + std::vector static_relocs_; +}; // End of Output_data_got_aarch64 + -// The aarch64 target class. -// See the ABI at -// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf template -class Target_aarch64 : public Sized_target +class AArch64_input_section; + + +template +class AArch64_output_section; + + +template +class AArch64_relobj; + + +// Stub type enum constants. + +enum { - public: - typedef Output_data_reloc - Reloc_section; - typedef typename elfcpp::Elf_types::Elf_Addr Address; + ST_NONE = 0, - Target_aarch64(const Target::Target_info* info = &aarch64_info) - : Sized_target(info), - got_(NULL), plt_(NULL), got_plt_(NULL), - global_offset_table_(NULL), rela_dyn_(NULL), - copy_relocs_(elfcpp::R_AARCH64_COPY) - { } + // Using adrp/add pair, 4 insns (including alignment) without mem access, + // the fastest stub. This has a limited jump distance, which is tested by + // aarch64_valid_for_adrp_p. + ST_ADRP_BRANCH = 1, - // Scan the relocations to determine unreferenced sections for - // garbage collection. - void - gc_process_relocs(Symbol_table* symtab, - Layout* layout, - Sized_relobj_file* object, - unsigned int data_shndx, - unsigned int sh_type, - const unsigned char* prelocs, - size_t reloc_count, - Output_section* output_section, - bool needs_special_offset_handling, - size_t local_symbol_count, - const unsigned char* plocal_symbols); + // Using ldr-absolute-address/br-register, 4 insns with 1 mem access, + // unlimited in jump distance. + ST_LONG_BRANCH_ABS = 2, - // Scan the relocations to look for symbol adjustments. - void - scan_relocs(Symbol_table* symtab, - Layout* layout, - Sized_relobj_file* object, - unsigned int data_shndx, - unsigned int sh_type, - const unsigned char* prelocs, - size_t reloc_count, - Output_section* output_section, - bool needs_special_offset_handling, - size_t local_symbol_count, - const unsigned char* plocal_symbols); + // Using ldr/calculate-pcrel/jump, 8 insns (including alignment) with 1 + // mem access, slowest one. Only used in position independent executables. + ST_LONG_BRANCH_PCREL = 3, - // Finalize the sections. - void - do_finalize_sections(Layout*, const Input_objects*, Symbol_table*); + // Stub for erratum 843419 handling. + ST_E_843419 = 4, - // Relocate a section. - void - relocate_section(const Relocate_info*, - unsigned int sh_type, - const unsigned char* prelocs, - size_t reloc_count, - Output_section* output_section, - bool needs_special_offset_handling, - unsigned char* view, - typename elfcpp::Elf_types::Elf_Addr view_address, - section_size_type view_size, - const Reloc_symbol_changes*); + // Stub for erratum 835769 handling. + ST_E_835769 = 5, - // Scan the relocs during a relocatable link. - void - scan_relocatable_relocs(Symbol_table* symtab, - Layout* layout, - Sized_relobj_file* object, - unsigned int data_shndx, - unsigned int sh_type, - const unsigned char* prelocs, - size_t reloc_count, - Output_section* output_section, - bool needs_special_offset_handling, - size_t local_symbol_count, - const unsigned char* plocal_symbols, - Relocatable_relocs*); + // Number of total stub types. + ST_NUMBER = 6 +}; - // Relocate a section during a relocatable link. - void - relocate_relocs( - const Relocate_info*, - unsigned int sh_type, - const unsigned char* prelocs, - size_t reloc_count, - Output_section* output_section, - typename elfcpp::Elf_types::Elf_Off offset_in_output_section, - const Relocatable_relocs*, - unsigned char* view, - typename elfcpp::Elf_types::Elf_Addr view_address, - section_size_type view_size, - unsigned char* reloc_view, - section_size_type reloc_view_size); - // Return the PLT section. - uint64_t - do_plt_address_for_global(const Symbol* gsym) const - { return this->plt_section()->address_for_global(gsym); } +// Struct that wraps insns for a particular stub. All stub templates are +// created/initialized as constants by Stub_template_repertoire. - uint64_t - do_plt_address_for_local(const Relobj* relobj, unsigned int symndx) const - { return this->plt_section()->address_for_local(relobj, symndx); } +template +struct Stub_template +{ + const typename AArch64_insn_utilities::Insntype* insns; + const int insn_num; +}; - // Return the number of entries in the PLT. - unsigned int - plt_entry_count() const; - //Return the offset of the first non-reserved PLT entry. - unsigned int - first_plt_entry_offset() const; +// Simple singleton class that creates/initializes/stores all types of stub +// templates. - // Return the size of each PLT entry. - unsigned int - plt_entry_size() const; +template +class Stub_template_repertoire +{ +public: + typedef typename AArch64_insn_utilities::Insntype Insntype; - protected: - void - do_select_as_default_target() + // Single static method to get stub template for a given stub type. + static const Stub_template* + get_stub_template(int type) { - gold_assert(aarch64_reloc_property_table == NULL); - aarch64_reloc_property_table = new AArch64_reloc_property_table(); + static Stub_template_repertoire singleton; + return singleton.stub_templates_[type]; } - virtual Output_data_plt_aarch64* - do_make_data_plt(Layout* layout, Output_data_space* got_plt) - { - return new Output_data_plt_aarch64_standard(layout, - got_plt); - } +private: + // Constructor - creates/initializes all stub templates. + Stub_template_repertoire(); + ~Stub_template_repertoire() + { } - Output_data_plt_aarch64* - make_data_plt(Layout* layout, Output_data_space* got_plt) - { - return this->do_make_data_plt(layout, got_plt); - } + // Disallowing copy ctor and copy assignment operator. + Stub_template_repertoire(Stub_template_repertoire&); + Stub_template_repertoire& operator=(Stub_template_repertoire&); - private: - // The class which scans relocations. - class Scan - { - public: - Scan() - : issued_non_pic_error_(false) - { } + // Data that stores all insn templates. + const Stub_template* stub_templates_[ST_NUMBER]; +}; // End of "class Stub_template_repertoire". - inline void - local(Symbol_table* symtab, Layout* layout, Target_aarch64* target, - Sized_relobj_file* object, - unsigned int data_shndx, - Output_section* output_section, - const elfcpp::Rela& reloc, unsigned int r_type, - const elfcpp::Sym& lsym, - bool is_discarded); - inline void - global(Symbol_table* symtab, Layout* layout, Target_aarch64* target, - Sized_relobj_file* object, - unsigned int data_shndx, - Output_section* output_section, - const elfcpp::Rela& reloc, unsigned int r_type, - Symbol* gsym); +// Constructor - creates/initilizes all stub templates. - inline bool - local_reloc_may_be_function_pointer(Symbol_table* , Layout* , - Target_aarch64* , - Sized_relobj_file* , - unsigned int , - Output_section* , - const elfcpp::Rela& , - unsigned int r_type, - const elfcpp::Sym&); +template +Stub_template_repertoire::Stub_template_repertoire() +{ + // Insn array definitions. + const static Insntype ST_NONE_INSNS[] = {}; - inline bool - global_reloc_may_be_function_pointer(Symbol_table* , Layout* , - Target_aarch64* , - Sized_relobj_file* , - unsigned int , - Output_section* , - const elfcpp::Rela& , - unsigned int r_type, - Symbol* gsym); + const static Insntype ST_ADRP_BRANCH_INSNS[] = + { + 0x90000010, /* adrp ip0, X */ + /* ADR_PREL_PG_HI21(X) */ + 0x91000210, /* add ip0, ip0, :lo12:X */ + /* ADD_ABS_LO12_NC(X) */ + 0xd61f0200, /* br ip0 */ + 0x00000000, /* alignment padding */ + }; + + const static Insntype ST_LONG_BRANCH_ABS_INSNS[] = + { + 0x58000050, /* ldr ip0, 0x8 */ + 0xd61f0200, /* br ip0 */ + 0x00000000, /* address field */ + 0x00000000, /* address fields */ + }; - private: - static void - unsupported_reloc_local(Sized_relobj_file*, - unsigned int r_type); + const static Insntype ST_LONG_BRANCH_PCREL_INSNS[] = + { + 0x58000090, /* ldr ip0, 0x10 */ + 0x10000011, /* adr ip1, #0 */ + 0x8b110210, /* add ip0, ip0, ip1 */ + 0xd61f0200, /* br ip0 */ + 0x00000000, /* address field */ + 0x00000000, /* address field */ + 0x00000000, /* alignment padding */ + 0x00000000, /* alignment padding */ + }; + + const static Insntype ST_E_843419_INSNS[] = + { + 0x00000000, /* Placeholder for erratum insn. */ + 0x14000000, /* b