diff --git a/gold/aarch64.cc b/gold/aarch64.cc index 2745776..aa1558f 100644 --- a/gold/aarch64.cc +++ b/gold/aarch64.cc @@ -22,10 +22,11 @@ #include "gold.h" #include #include +#include #include "elfcpp.h" #include "dwarf.h" #include "parameters.h" #include "reloc.h" @@ -574,40 +575,440 @@ class AArch64_input_section; template class AArch64_output_section; +template +class AArch64_relobj; + + +// Stub type enum constants wrapped in a struct, so we refer to them as +// Stub_type::ST_XXX instead of ST_XXX. +struct Stub_type +{ + enum + { + ST_NONE = 0, + + // 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, + + // Using ldr-absolute-address/br-register, 4 insns with 1 mem access, + // unlimited in jump distance. + ST_LONG_BRANCH_ABS = 2, + + // 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, + + // Stub for erratum 843419 handling. + ST_E_843419 = 4, + + // Number of total stub types. + ST_NUMBER = 5 + }; + +private: + // Never allow any such instance. + Stub_type(); +}; + + +// Class that wraps insns for a particular stub. All stub templates are +// created/initialized as constants by Stub_template_repertoire. + +template +class Stub_template +{ +public: + typedef typename AArch64_insn_utilities::Insntype Insntype; + + Stub_template(const Insntype* insns, const int insn_num) + : insns_(insns), insn_num_(insn_num) + {} + + ~Stub_template() {} + + // Get number of stub insns. + int + insn_num() const + { return this->insn_num_; } + + // Get the stub insn array. + const Insntype* + insns() const + { return this->insns_; } + +private: + // Stub insn array. + const Insntype* insns_; + // Number of stub insns. + const int insn_num_; +}; // End of "class Stub_template". + + +// Simple singleton class that creates/initializes/stores all types of stub +// templates. + +template +class Stub_template_repertoire +{ +public: + typedef typename AArch64_insn_utilities::Insntype Insntype; + + // Get singleton instance. + static Stub_template_repertoire* + get_instance() + { + static Stub_template_repertoire singleton; + return &singleton; + } + + // Get stub template for a given stub type. + Stub_template* + get_stub_template(int type) + { return this->stub_templates_[type]; } + +private: + // Constructor - creates/initilizes all stub templates. + Stub_template_repertoire(); + + // Destructor - deletes all stub templates. + ~Stub_template_repertoire(); + + Stub_template_repertoire(Stub_template_repertoire&); + Stub_template_repertoire& operator = (Stub_template_repertoire&); + + // Data that stores all insn templates. + Stub_template* stub_templates_[Stub_type::ST_NUMBER]; +}; // End of "class Stub_template_repertoire". + + +// Constructor - creates/initilizes all stub templates. + +template +Stub_template_repertoire::Stub_template_repertoire() +{ + // Insn array definitions. + const static Insntype ST_NONE_INSNS[] = {}; + + 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 */ + }; + + 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