This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: [gold][aarch64] Patch for erratum-843419 (2 of 2 - fix erratum occurrences)
- From: Han Shen <shenhan at google dot com>
- To: Cary Coutant <ccoutant at gmail dot com>, binutils <binutils at sourceware dot org>
- Cc: Luis Lozano <llozano at google dot com>, Bhaskar <bjanakiraman at google dot com>
- Date: Fri, 5 Jun 2015 11:49:51 -0700
- Subject: Re: [gold][aarch64] Patch for erratum-843419 (2 of 2 - fix erratum occurrences)
- Authentication-results: sourceware.org; auth=none
- References: <CACkGtrj3SiMVVJAJK3k4J9nikLXVOZx_evKWBwAFPR3Y3QHnMQ at mail dot gmail dot com> <CAJimCsF4oEm0iZgCfwe_5D1=j35-e9n0OWLm7-1Z04mR7Pk6UQ at mail dot gmail dot com>
Hi Cary, thanks for the review. (I also just came back from an offsite...)
Attached the new patch e843419-2nd.patch. Also
"diff-against-prev-patch.patch" for ease of incremental review.
On Mon, Jun 1, 2015 at 2:39 PM, Cary Coutant <ccoutant@gmail.com> wrote:
>> Hi Cary, here is the 2nd patch for erratum 843419 - fixing the erratum.
>
> Sorry for the delay. I'm back from vacation now.
>
> -cary
>
>
> +// 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();
> +};
>
> Instead of using a struct to get the effect of a namespace, why
> not just use a namespace directly? (It's not clear to me that you
> really need to enclose these constants in a namespace at all. The
> entire source file is already in an anonymous namespace, so
> there's no worry about conflicting with any names from another
> source file.)
Removed wrapping struct, and define them as global enum constants.
>
> +// Simple singleton class that creates/initializes/stores all types of stub
> +// templates.
> +
> +template<bool big_endian>
> +class Stub_template_repertoire
> +{
> +public:
> + typedef typename AArch64_insn_utilities<big_endian>::Insntype Insntype;
> +
> + // Get singleton instance.
> + static Stub_template_repertoire<big_endian>*
> + get_instance()
> + {
> + static Stub_template_repertoire<big_endian> singleton;
> + return &singleton;
> + }
> +
> + // Get stub template for a given stub type.
> + Stub_template<big_endian>*
> + 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&);
>
> No spaces around "=".
Done
>
> I'd suggest adding a comment that you're disallowing these
> constructors.
Done
>
> +
> + // Data that stores all insn templates.
> + Stub_template<big_endian>* stub_templates_[Stub_type::ST_NUMBER];
> +}; // End of "class Stub_template_repertoire".
>
> This class seems overly complex. It seems to me that it would be
> simpler and clearer to make Stub_template a simple struct with
> two fields, and make your repertoire a statically-initialized
> array.
Reduced Stub_template to POD with 2 constant fields.
>
> If you decide to stick with the singleton class, however, I see
> no need for the get_instance() method -- just make
> get_stub_template() a static member, and put the singleton there.
Keep Stub_template_repertoire as a singleton class but removed get_instance.
Also in ctor, use static variable to avoid explicit deletion in
~Stub_template_repertoire dtor.
>
> +// Constructor - creates/initilizes all stub templates.
>
> "initializes"
Done
>
> + // The stub offset. Note this has difference interpretations between an
> + // Reloc_stub and an Erratum_stub. For Reloc_stub this is the offset from the
> + // beginning of the containng stub_table, whereas for Erratum_stub, this is
>
> "containing"
Done
>
> + // the offset from the end of reloc_stubs.
> + section_offset_type offset_;
> + // Stub type.
> + const int type_;
> + // Stub template that provides stub insn information.
> + const Stub_template<big_endian>* stub_template_;
>
> This is always going to be get_stub_templates(this->type_), so why not make
> this a method instead of a data member?
Yup, this is good point. Done.
>
> +// Erratum stub class. An erratum stub differs from a reloc stub in that for
> +// each erratum occurrence, we generates an erratum stub, we never
> share erratum
> +// stubs, whereas for reloc stubs, different branches insns share a
> single reloc
> +// stub as long as the branch targets are the same.
>
> "... we generate an erratum stub. We never share ..."
Done.
>
> 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.
Added this to the comment.
>
> + // For current implemnted erratum 843419, (and 835769 which is to be
> + // implemented soon), the first insn in the stub is always a copy of the
> + // problmatic insn (in 843419, the mem access insn), followed by a jump-back.
>
> "problematic"
>
> +// Find all the errata for a given input sectin. The return value is a pair of
>
> "section"
Done.
>
> + stub_b_insn_address = stub_address
> + + 1 * AArch64_insn_utilities<big_endian>::BYTES_PER_INSN;
>
> Need parentheses around the split expression. It might look nicer if
> you declare a local const with a shorter name:
>
> const int BPI = AArch64_insn_utilities<big_endian>::BYTES_PER_INSN
> ...
> stub_b_insn_address = stub_address + 1 * BPI;
Done.
Thanks,
Han
diff --git a/gold/aarch64.cc b/gold/aarch64.cc
index 2745776..130fcc2 100644
--- a/gold/aarch64.cc
+++ b/gold/aarch64.cc
@@ -24,6 +24,7 @@
#include <cstring>
#include <map>
+#include <set>
#include "elfcpp.h"
#include "dwarf.h"
@@ -576,36 +577,398 @@ template<int size, bool big_endian>
class AArch64_output_section;
+template<int size, bool big_endian>
+class AArch64_relobj;
+
+
+// Stub type enum constants.
+
+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
+};
+
+
+// Struct that wraps insns for a particular stub. All stub templates are
+// created/initialized as constants by Stub_template_repertoire.
+
+template<bool big_endian>
+struct Stub_template
+{
+ const typename AArch64_insn_utilities<big_endian>::Insntype* insns;
+ const int insn_num;
+};
+
+
+// Simple singleton class that creates/initializes/stores all types of stub
+// templates.
+
+template<bool big_endian>
+class Stub_template_repertoire
+{
+public:
+ typedef typename AArch64_insn_utilities<big_endian>::Insntype Insntype;
+
+ // Single static method to get stub template for a given stub type.
+ static const Stub_template<big_endian>*
+ get_stub_template(int type)
+ {
+ static Stub_template_repertoire<big_endian> singleton;
+ return singleton.stub_templates_[type];
+ }
+
+private:
+ // Constructor - creates/initializes all stub templates.
+ Stub_template_repertoire();
+ ~Stub_template_repertoire()
+ { }
+
+ // Disallowing copy ctor and copy assignment operator.
+ Stub_template_repertoire(Stub_template_repertoire&);
+ Stub_template_repertoire& operator=(Stub_template_repertoire&);
+
+ // Data that stores all insn templates.
+ const Stub_template<big_endian>* stub_templates_[ST_NUMBER];
+}; // End of "class Stub_template_repertoire".
+
+
+// Constructor - creates/initilizes all stub templates.
+
+template<bool big_endian>
+Stub_template_repertoire<big_endian>::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 <label> */
+ };
+
+#define install_insn_template(T) \
+ const static Stub_template<big_endian> template_##T = { \
+ T##_INSNS, sizeof(T##_INSNS) / sizeof(T##_INSNS[0]) }; \
+ this->stub_templates_[T] = &template_##T
+
+ install_insn_template(ST_NONE);
+ install_insn_template(ST_ADRP_BRANCH);
+ install_insn_template(ST_LONG_BRANCH_ABS);
+ install_insn_template(ST_LONG_BRANCH_PCREL);
+ install_insn_template(ST_E_843419);
+
+#undef install_insn_template
+}
+
+
+// Base class for stubs.
+
+template<int size, bool big_endian>
+class Stub_base
+{
+public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_address;
+ typedef typename AArch64_insn_utilities<big_endian>::Insntype Insntype;
+
+ static const AArch64_address invalid_address =
+ static_cast<AArch64_address>(-1);
+
+ static const section_offset_type invalid_offset =
+ static_cast<section_offset_type>(-1);
+
+ Stub_base(int type)
+ : destination_address_(invalid_address),
+ offset_(invalid_offset),
+ type_(type)
+ {}
+
+ ~Stub_base()
+ {}
+
+ // Get stub type.
+ int
+ type() const
+ { return this->type_; }
+
+ // Get stub template that provides stub insn information.
+ const Stub_template<big_endian>*
+ stub_template() const
+ {
+ return Stub_template_repertoire<big_endian>::
+ get_stub_template(this->type());
+ }
+
+ // Get destination address.
+ AArch64_address
+ destination_address() const
+ {
+ gold_assert(this->destination_address_ != this->invalid_address);
+ return this->destination_address_;
+ }
+
+ // Set destination address.
+ void
+ set_destination_address(AArch64_address address)
+ {
+ gold_assert(address != this->invalid_address);
+ this->destination_address_ = address;
+ }
+
+ // Reset the destination address.
+ void
+ reset_destination_address()
+ { this->destination_address_ = this->invalid_address; }
+
+ // Get offset of code stub. For Reloc_stub, it is the offset from the
+ // beginning of its containing stub table; for Erratum_stub, it is the offset
+ // from the end of reloc_stubs.
+ section_offset_type
+ offset() const
+ {
+ gold_assert(this->offset_ != this->invalid_offset);
+ return this->offset_;
+ }
+
+ // Set stub offset.
+ void
+ set_offset(section_offset_type offset)
+ { this->offset_ = offset; }
+
+ // Return the stub insn.
+ const Insntype*
+ insns() const
+ { return this->stub_template()->insns; }
+
+ // Return num of stub insns.
+ unsigned int
+ insn_num() const
+ { return this->stub_template()->insn_num; }
+
+ // Get size of the stub.
+ int
+ stub_size() const
+ {
+ return this->insn_num() *
+ AArch64_insn_utilities<big_endian>::BYTES_PER_INSN;
+ }
+
+ // Write stub to output file.
+ void
+ write(unsigned char* view, section_size_type view_size)
+ { this->do_write(view, view_size); }
+
+protected:
+ // Abstract method to be implemented by sub-classes.
+ virtual void
+ do_write(unsigned char*, section_size_type) = 0;
+
+private:
+ // The last insn of a stub is a jump to destination insn. This field records
+ // the destination address.
+ AArch64_address destination_address_;
+ // The stub offset. Note this has difference interpretations between an
+ // Reloc_stub and an Erratum_stub. For Reloc_stub this is the offset from the
+ // beginning of the containing stub_table, whereas for Erratum_stub, this is
+ // the offset from the end of reloc_stubs.
+ section_offset_type offset_;
+ // Stub type.
+ const int type_;
+}; // End of "Stub_base".
+
+
+// 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
+// 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.)
+
+template<int size, bool big_endian>
+class Erratum_stub : public Stub_base<size, big_endian>
+{
+public:
+ typedef AArch64_relobj<size, big_endian> The_aarch64_relobj;
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_address;
+ typedef typename AArch64_insn_utilities<big_endian>::Insntype Insntype;
+
+ static const int STUB_ADDR_ALIGN = 4;
+
+ static const Insntype invalid_insn = static_cast<Insntype>(-1);
+
+ Erratum_stub(The_aarch64_relobj* relobj, int type,
+ unsigned shndx, unsigned int sh_offset)
+ : Stub_base<size, big_endian>(type), relobj_(relobj),
+ shndx_(shndx), sh_offset_(sh_offset),
+ erratum_insn_(invalid_insn),
+ erratum_address_(this->invalid_address)
+ {}
+
+ ~Erratum_stub() {}
+
+ // Return the object that contains the erratum.
+ The_aarch64_relobj*
+ relobj()
+ { return this->relobj_; }
+
+ // Get section index of the erratum.
+ unsigned int
+ shndx() const
+ { return this->shndx_; }
+
+ // Get section offset of the erratum.
+ unsigned int
+ sh_offset() const
+ { return this->sh_offset_; }
+
+ // Get the erratum insn. This is the insn located at erratum_insn_address.
+ Insntype
+ erratum_insn() const
+ {
+ gold_assert(this->erratum_insn_ != this->invalid_insn);
+ return this->erratum_insn_;
+ }
+
+ // Set the insn that the erratum happens to.
+ void
+ set_erratum_insn(Insntype insn)
+ { this->erratum_insn_ = insn; }
+
+ // Return the address where an erratum must be done.
+ AArch64_address
+ erratum_address() const
+ {
+ gold_assert(this->erratum_address_ != this->invalid_address);
+ return this->erratum_address_;
+ }
+
+ // Set the address where an erratum must be done.
+ void
+ set_erratum_address(AArch64_address addr)
+ { this->erratum_address_ = addr; }
+
+ // Comparator used to group Erratum_stubs in a set by (obj, shndx,
+ // sh_offset). We do not include 'type' in the calculation, becuase there is
+ // at most one stub type at (obj, shndx, sh_offset).
+ bool
+ operator<(const Erratum_stub<size, big_endian>& k) const
+ {
+ if (this == &k)
+ return false;
+ // We group stubs by relobj.
+ if (this->relobj_ != k.relobj_)
+ return this->relobj_ < k.relobj_;
+ // Then by section index.
+ if (this->shndx_ != k.shndx_)
+ return this->shndx_ < k.shndx_;
+ // Lastly by section offset.
+ return this->sh_offset_ < k.sh_offset_;
+ }
+
+protected:
+ virtual void
+ do_write(unsigned char*, section_size_type);
+
+private:
+ // The object that needs to be fixed.
+ The_aarch64_relobj* relobj_;
+ // The shndx in the object that needs to be fixed.
+ const unsigned int shndx_;
+ // The section offset in the obejct that needs to be fixed.
+ const unsigned int sh_offset_;
+ // The insn to be fixed.
+ Insntype erratum_insn_;
+ // The address of the above insn.
+ AArch64_address erratum_address_;
+}; // End of "Erratum_stub".
+
+
+// Comparator used in set definition.
+template<int size, bool big_endian>
+struct Erratum_stub_less
+{
+ bool
+ operator()(const Erratum_stub<size, big_endian>* s1,
+ const Erratum_stub<size, big_endian>* s2) const
+ { return *s1 < *s2; }
+};
+
+// Erratum_stub implementation for writing stub to output file.
+
+template<int size, bool big_endian>
+void
+Erratum_stub<size, big_endian>::do_write(unsigned char* view, section_size_type)
+{
+ typedef typename elfcpp::Swap<32, big_endian>::Valtype Insntype;
+ const Insntype* insns = this->insns();
+ uint32_t num_insns = this->insn_num();
+ Insntype* ip = reinterpret_cast<Insntype*>(view);
+ // For current implemnted erratum 843419, (and 835769 which is to be
+ // implemented soon), the first insn in the stub is always a copy of the
+ // problematic insn (in 843419, the mem access insn), followed by a jump-back.
+ elfcpp::Swap<32, big_endian>::writeval(ip, this->erratum_insn());
+ for (uint32_t i = 1; i < num_insns; ++i)
+ elfcpp::Swap<32, big_endian>::writeval(ip + i, insns[i]);
+}
+
+
// Reloc stub class.
template<int size, bool big_endian>
-class Reloc_stub
+class Reloc_stub : public Stub_base<size, big_endian>
{
public:
typedef Reloc_stub<size, big_endian> This;
typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_address;
- // Do not change the value of the enums, they are used to index into
- // stub_insns array.
- typedef 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_type;
-
// Branch range. This is used to calculate the section group size, as well as
// determine whether a stub is needed.
static const int MAX_BRANCH_OFFSET = ((1 << 25) - 1) << 2;
@@ -635,84 +998,24 @@ class Reloc_stub
// Determine the stub type for a certain relocation or ST_NONE, if no stub is
// needed.
- static Stub_type
+ static int
stub_type_for_reloc(unsigned int r_type, AArch64_address address,
AArch64_address target);
- Reloc_stub(Stub_type stub_type)
- : stub_type_(stub_type), offset_(invalid_offset),
- destination_address_(invalid_address)
+ Reloc_stub(int type)
+ : Stub_base<size, big_endian>(type)
{ }
~Reloc_stub()
{ }
- // Return offset of code stub from beginning of its containing stub table.
- section_offset_type
- offset() const
- {
- gold_assert(this->offset_ != invalid_offset);
- return this->offset_;
- }
-
- // Set offset of code stub from beginning of its containing stub table.
- void
- set_offset(section_offset_type offset)
- { this->offset_ = offset; }
-
- // Return destination address.
- AArch64_address
- destination_address() const
- {
- gold_assert(this->destination_address_ != this->invalid_address);
- return this->destination_address_;
- }
-
- // Set destination address.
- void
- set_destination_address(AArch64_address address)
- {
- gold_assert(address != this->invalid_address);
- this->destination_address_ = address;
- }
-
- // Reset the destination address.
- void
- reset_destination_address()
- { this->destination_address_ = this->invalid_address; }
-
- // Return the stub type.
- Stub_type
- stub_type() const
- { return stub_type_; }
-
- // Return the stub size.
- uint32_t
- stub_size() const
- { return this->stub_insn_number() * BYTES_PER_INSN; }
-
- // Return the instruction number of this stub instance.
- int
- stub_insn_number() const
- { return stub_insns_[this->stub_type_][0]; }
-
- // Note the first "insn" is the number of total insns in this array.
- const uint32_t*
- stub_insns() const
- { return stub_insns_[this->stub_type_]; }
-
- // Write stub to output file.
- void
- write(unsigned char* view, section_size_type view_size)
- { this->do_write(view, view_size); }
-
// The key class used to index the stub instance in the stub table's stub map.
class Key
{
public:
- Key(Stub_type stub_type, const Symbol* symbol, const Relobj* relobj,
+ Key(int type, const Symbol* symbol, const Relobj* relobj,
unsigned int r_sym, int32_t addend)
- : stub_type_(stub_type), addend_(addend)
+ : type_(type), addend_(addend)
{
if (symbol != NULL)
{
@@ -731,9 +1034,9 @@ class Reloc_stub
{ }
// Return stub type.
- Stub_type
- stub_type() const
- { return this->stub_type_; }
+ int
+ type() const
+ { return this->type_; }
// Return the local symbol index or invalid_index.
unsigned int
@@ -754,7 +1057,7 @@ class Reloc_stub
bool
eq(const Key& k) const
{
- return ((this->stub_type_ == k.stub_type_)
+ return ((this->type_ == k.type_)
&& (this->r_sym_ == k.r_sym_)
&& ((this->r_sym_ != Reloc_stub::invalid_index)
? (this->u_.relobj == k.u_.relobj)
@@ -771,7 +1074,7 @@ class Reloc_stub
? this->u_.relobj->name().c_str()
: this->u_.symbol->name());
// We only have 4 stub types.
- size_t stub_type_hash_value = 0x03 & this->stub_type_;
+ size_t stub_type_hash_value = 0x03 & this->type_;
return (name_hash_value
^ stub_type_hash_value
^ ((this->r_sym_ & 0x3fff) << 2)
@@ -795,7 +1098,7 @@ class Reloc_stub
private:
// Stub type.
- const Stub_type stub_type_;
+ const int type_;
// If this is a local symbol, this is the index in the defining object.
// Otherwise, it is invalid_index for a global symbol.
unsigned int r_sym_;
@@ -820,17 +1123,7 @@ class Reloc_stub
do_write(unsigned char*, section_size_type);
private:
- static const section_offset_type invalid_offset =
- static_cast<section_offset_type>(-1);
static const unsigned int invalid_index = static_cast<unsigned int>(-1);
- static const AArch64_address invalid_address =
- static_cast<AArch64_address>(-1);
-
- static const uint32_t stub_insns_[][10];
-
- const Stub_type stub_type_;
- section_offset_type offset_;
- AArch64_address destination_address_;
}; // End of Reloc_stub
@@ -842,66 +1135,19 @@ Reloc_stub<size, big_endian>::
do_write(unsigned char* view, section_size_type)
{
typedef typename elfcpp::Swap<32, big_endian>::Valtype Insntype;
- const uint32_t* insns = this->stub_insns();
- uint32_t num_insns = this->stub_insn_number();
+ const uint32_t* insns = this->insns();
+ uint32_t num_insns = this->insn_num();
Insntype* ip = reinterpret_cast<Insntype*>(view);
- for (uint32_t i = 1; i <= num_insns; ++i)
- elfcpp::Swap<32, big_endian>::writeval(ip + i - 1, insns[i]);
+ for (uint32_t i = 0; i < num_insns; ++i)
+ elfcpp::Swap<32, big_endian>::writeval(ip + i, insns[i]);
}
-// Stubs instructions definition.
-
-template<int size, bool big_endian>
-const uint32_t
-Reloc_stub<size, big_endian>::stub_insns_[][10] =
- {
- // The first element of each group is the num of the insns.
-
- // ST_NONE
- {0, 0},
-
- // ST_ADRP_BRANCH
- {
- 4,
- 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 */
- },
-
- // ST_LONG_BRANCH_ABS
- {
- 4,
- 0x58000050, /* ldr ip0, 0x8 */
- 0xd61f0200, /* br ip0 */
- 0x00000000, /* address field */
- 0x00000000, /* address fields */
- },
-
- // ST_LONG_BRANCH_PCREL
- {
- 8,
- 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 */
- }
- };
-
-
// Determine the stub type for a certain relocation or ST_NONE, if no stub is
// needed.
template<int size, bool big_endian>
-inline
-typename Reloc_stub<size, big_endian>::Stub_type
+inline int
Reloc_stub<size, big_endian>::stub_type_for_reloc(
unsigned int r_type, AArch64_address location, AArch64_address dest)
{
@@ -937,9 +1183,12 @@ class Stub_table : public Output_data
public:
typedef Target_aarch64<size, big_endian> The_target_aarch64;
typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_address;
+ typedef AArch64_relobj<size, big_endian> The_aarch64_relobj;
typedef AArch64_input_section<size, big_endian> The_aarch64_input_section;
typedef Reloc_stub<size, big_endian> The_reloc_stub;
typedef typename The_reloc_stub::Key The_reloc_stub_key;
+ typedef Erratum_stub<size, big_endian> The_erratum_stub;
+ typedef Erratum_stub_less<size, big_endian> The_erratum_stub_less;
typedef typename The_reloc_stub_key::hash The_reloc_stub_key_hash;
typedef typename The_reloc_stub_key::equal_to The_reloc_stub_key_equal_to;
typedef Stub_table<size, big_endian> The_stub_table;
@@ -949,8 +1198,12 @@ class Stub_table : public Output_data
typedef typename Reloc_stub_map::const_iterator Reloc_stub_map_const_iter;
typedef Relocate_info<size, big_endian> The_relocate_info;
+ typedef std::set<The_erratum_stub*, The_erratum_stub_less> Erratum_stub_set;
+ typedef typename Erratum_stub_set::iterator Erratum_stub_set_iter;
+
Stub_table(The_aarch64_input_section* owner)
- : Output_data(), owner_(owner), reloc_stubs_size_(0), prev_data_size_(0)
+ : Output_data(), owner_(owner), reloc_stubs_size_(0),
+ erratum_stubs_size_(0), prev_data_size_(0)
{ }
~Stub_table()
@@ -963,7 +1216,7 @@ class Stub_table : public Output_data
// Whether this stub table is empty.
bool
empty() const
- { return reloc_stubs_.empty(); }
+ { return reloc_stubs_.empty() && erratum_stubs_.empty(); }
// Return the current data size.
off_t
@@ -975,6 +1228,32 @@ class Stub_table : public Output_data
void
add_reloc_stub(The_reloc_stub* stub, const The_reloc_stub_key& key);
+ // Add an erratum stub into the erratum stub set. The set is ordered by
+ // (relobj, shndx, sh_offset).
+ void
+ add_erratum_stub(The_erratum_stub* stub);
+
+ // Find if such erratum exists for any given (obj, shndx, sh_offset).
+ The_erratum_stub*
+ find_erratum_stub(The_aarch64_relobj* a64relobj,
+ unsigned int shndx, unsigned int sh_offset);
+
+ // Find all the erratums for a given input section. The return value is a pair
+ // of iterators [begin, end).
+ std::pair<Erratum_stub_set_iter, Erratum_stub_set_iter>
+ find_erratum_stubs_for_input_section(The_aarch64_relobj* a64relobj,
+ unsigned int shndx);
+
+ // Compute the erratum stub address.
+ AArch64_address
+ erratum_stub_address(The_erratum_stub* stub) const
+ {
+ AArch64_address r = align_address(this->address() + this->reloc_stubs_size_,
+ The_erratum_stub::STUB_ADDR_ALIGN);
+ r += stub->offset();
+ return r;
+ }
+
// Finalize stubs. No-op here, just for completeness.
void
finalize_stubs()
@@ -1003,7 +1282,9 @@ class Stub_table : public Output_data
update_data_size_changed_p()
{
// No addralign changed here.
- off_t s = this->reloc_stubs_size_;
+ off_t s = align_address(this->reloc_stubs_size_,
+ The_erratum_stub::STUB_ADDR_ALIGN)
+ + this->erratum_stubs_size_;
bool changed = (s != this->prev_data_size_);
this->prev_data_size_ = s;
return changed;
@@ -1017,7 +1298,10 @@ class Stub_table : public Output_data
// Return the required alignment.
uint64_t
do_addralign() const
- { return The_reloc_stub::STUB_ADDR_ALIGN; }
+ {
+ return std::max(The_reloc_stub::STUB_ADDR_ALIGN,
+ The_erratum_stub::STUB_ADDR_ALIGN);
+ }
// Reset address and file offset.
void
@@ -1045,13 +1329,79 @@ class Stub_table : public Output_data
The_aarch64_input_section* owner_;
// The relocation stubs.
Reloc_stub_map reloc_stubs_;
+ // The erratum stubs.
+ Erratum_stub_set erratum_stubs_;
// Size of reloc stubs.
off_t reloc_stubs_size_;
+ // Size of erratum stubs.
+ off_t erratum_stubs_size_;
// data size of this in the previous pass.
off_t prev_data_size_;
}; // End of Stub_table
+// Add an erratum stub into the erratum stub set. The set is ordered by
+// (relobj, shndx, sh_offset).
+
+template<int size, bool big_endian>
+void
+Stub_table<size, big_endian>::add_erratum_stub(The_erratum_stub* stub)
+{
+ std::pair<Erratum_stub_set_iter, bool> ret =
+ this->erratum_stubs_.insert(stub);
+ gold_assert(ret.second);
+ this->erratum_stubs_size_ = align_address(
+ this->erratum_stubs_size_, The_erratum_stub::STUB_ADDR_ALIGN);
+ stub->set_offset(this->erratum_stubs_size_);
+ this->erratum_stubs_size_ += stub->stub_size();
+}
+
+
+// Find if such erratum exists for givein (obj, shndx, sh_offset).
+
+template<int size, bool big_endian>
+Erratum_stub<size, big_endian>*
+Stub_table<size, big_endian>::find_erratum_stub(
+ The_aarch64_relobj* a64relobj, unsigned int shndx, unsigned int sh_offset)
+{
+ // A dummy object used as key to search in the set.
+ The_erratum_stub key(a64relobj, ST_NONE,
+ shndx, sh_offset);
+ Erratum_stub_set_iter i = this->erratum_stubs_.find(&key);
+ if (i != this->erratum_stubs_.end())
+ {
+ The_erratum_stub* stub(*i);
+ gold_assert(stub->erratum_insn() != 0);
+ return stub;
+ }
+ return NULL;
+}
+
+
+// Find all the errata for a given input section. The return value is a pair of
+// iterators [begin, end).
+
+template<int size, bool big_endian>
+std::pair<typename Stub_table<size, big_endian>::Erratum_stub_set_iter,
+ typename Stub_table<size, big_endian>::Erratum_stub_set_iter>
+Stub_table<size, big_endian>::find_erratum_stubs_for_input_section(
+ The_aarch64_relobj* a64relobj, unsigned int shndx)
+{
+ typedef std::pair<Erratum_stub_set_iter, Erratum_stub_set_iter> Result_pair;
+ Erratum_stub_set_iter start, end;
+ The_erratum_stub low_key(a64relobj, ST_NONE, shndx, 0);
+ start = this->erratum_stubs_.lower_bound(&low_key);
+ if (start == this->erratum_stubs_.end())
+ return Result_pair(this->erratum_stubs_.end(),
+ this->erratum_stubs_.end());
+ end = start;
+ while (end != this->erratum_stubs_.end() &&
+ (*end)->relobj() == a64relobj && (*end)->shndx() == shndx)
+ ++end;
+ return Result_pair(start, end);
+}
+
+
// Add a STUB using KEY. The caller is responsible for avoiding addition
// if a STUB with the same key has already been added.
@@ -1060,7 +1410,7 @@ void
Stub_table<size, big_endian>::add_reloc_stub(
The_reloc_stub* stub, const The_reloc_stub_key& key)
{
- gold_assert(stub->stub_type() == key.stub_type());
+ gold_assert(stub->type() == key.type());
this->reloc_stubs_[key] = stub;
// Assign stub offset early. We can do this because we never remove
@@ -1091,6 +1441,35 @@ relocate_stubs(const The_relocate_info* relinfo,
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)
+ {
+ 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:
+ // 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;
+ }
+ }
}
@@ -1140,6 +1519,17 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
stub->write(oview + stub->offset(), stub->stub_size());
}
+ // Write erratum stubs.
+ unsigned int erratum_stub_start_offset =
+ align_address(this->reloc_stubs_size_, The_erratum_stub::STUB_ADDR_ALIGN);
+ for (typename Erratum_stub_set::iterator p = this->erratum_stubs_.begin();
+ p != this->erratum_stubs_.end(); ++p)
+ {
+ The_erratum_stub* stub(*p);
+ stub->write(oview + erratum_stub_start_offset + stub->offset(),
+ stub->stub_size());
+ }
+
of->write_output_view(this->offset(), oview_size, oview);
}
@@ -1155,6 +1545,8 @@ class AArch64_relobj : public Sized_relobj_file<size, big_endian>
typedef AArch64_input_section<size, big_endian> The_aarch64_input_section;
typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_address;
typedef Stub_table<size, big_endian> The_stub_table;
+ typedef Erratum_stub<size, big_endian> The_erratum_stub;
+ typedef typename The_stub_table::Erratum_stub_set_iter Erratum_stub_set_iter;
typedef std::vector<The_stub_table*> Stub_table_list;
static const AArch64_address invalid_address =
static_cast<AArch64_address>(-1);
@@ -1258,6 +1650,10 @@ class AArch64_relobj : public Sized_relobj_file<size, big_endian>
Stringpool_template<char>*);
private:
+ // Fix all errata in the object.
+ void
+ fix_errata(typename Sized_relobj_file<size, big_endian>::Views* pviews);
+
// Whether a section needs to be scanned for relocation stubs.
bool
section_needs_reloc_stub_scanning(const elfcpp::Shdr<size, big_endian>&,
@@ -1353,6 +1749,48 @@ AArch64_relobj<size, big_endian>::do_count_local_symbols(
}
+// Fix all errata in the object.
+
+template<int size, bool big_endian>
+void
+AArch64_relobj<size, big_endian>::fix_errata(
+ typename Sized_relobj_file<size, big_endian>::Views* pviews)
+{
+ typedef typename elfcpp::Swap<32,big_endian>::Valtype Insntype;
+ unsigned int shnum = this->shnum();
+ for (unsigned int i = 1; i < shnum; ++i)
+ {
+ The_stub_table* stub_table = this->stub_table(i);
+ if (!stub_table)
+ continue;
+ 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;
+ 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.
+ Insntype* ip =
+ reinterpret_cast<Insntype*>(pview.view + stub->sh_offset());
+ Insntype insn_to_fix = ip[0];
+ gold_assert(insn_to_fix == stub->erratum_insn());
+ gold_assert(pview.address + stub->sh_offset()
+ == stub->erratum_address());
+
+ 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);
+ ++p;
+ }
+ }
+}
+
+
// Relocate sections.
template<int size, bool big_endian>
@@ -1370,6 +1808,9 @@ AArch64_relobj<size, big_endian>::do_relocate_sections(
if (parameters->options().relocatable())
return;
+ if (parameters->options().fix_cortex_a53_843419())
+ this->fix_errata(pviews);
+
Relocate_info<size, big_endian> relinfo;
relinfo.symtab = symtab;
relinfo.layout = layout;
@@ -2088,7 +2529,7 @@ class Target_aarch64 : public Sized_target<size, big_endian>
typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
typedef AArch64_relobj<size, big_endian> The_aarch64_relobj;
typedef Reloc_stub<size, big_endian> The_reloc_stub;
- typedef typename The_reloc_stub::Stub_type The_reloc_stub_type;
+ typedef Erratum_stub<size, big_endian> The_erratum_stub;
typedef typename Reloc_stub<size, big_endian>::Key The_reloc_stub_key;
typedef Stub_table<size, big_endian> The_stub_table;
typedef std::vector<The_stub_table*> Stub_table_list;
@@ -3028,9 +3469,9 @@ Target_aarch64<size, big_endian>::scan_reloc_for_stub(
gold_unreachable();
}
- typename The_reloc_stub::Stub_type stub_type = The_reloc_stub::
+ int stub_type = The_reloc_stub::
stub_type_for_reloc(r_type, address, destination);
- if (stub_type == The_reloc_stub::ST_NONE)
+ if (stub_type == ST_NONE)
return;
The_stub_table* stub_table = aarch64_relobj->stub_table(relinfo->data_shndx);
@@ -3284,20 +3725,20 @@ relocate_stub(The_reloc_stub* stub,
typedef typename elfcpp::Swap<32,big_endian>::Valtype Insntype;
Insntype* ip = reinterpret_cast<Insntype*>(view);
- int insn_number = stub->stub_insn_number();
- const uint32_t* insns = stub->stub_insns();
+ int insn_number = stub->insn_num();
+ const uint32_t* insns = stub->insns();
// Check the insns are really those stub insns.
for (int i = 0; i < insn_number; ++i)
{
Insntype insn = elfcpp::Swap<32,big_endian>::readval(ip + i);
- gold_assert(((uint32_t)insn == insns[i+1]));
+ gold_assert(((uint32_t)insn == insns[i]));
}
Address dest = stub->destination_address();
- switch(stub->stub_type())
+ switch(stub->type())
{
- case The_reloc_stub::ST_ADRP_BRANCH:
+ case ST_ADRP_BRANCH:
{
// 1st reloc is ADR_PREL_PG_HI21
The_reloc_functions_status status =
@@ -3318,12 +3759,12 @@ relocate_stub(The_reloc_stub* stub,
}
break;
- case The_reloc_stub::ST_LONG_BRANCH_ABS:
+ case ST_LONG_BRANCH_ABS:
// 1st reloc is R_AARCH64_PREL64, at offset 8
elfcpp::Swap<64,big_endian>::writeval(view + 8, dest);
break;
- case The_reloc_stub::ST_LONG_BRANCH_PCREL:
+ case ST_LONG_BRANCH_PCREL:
{
// "PC" calculation is the 2nd insn in the stub.
uint64_t offset = dest - (address + 4);
@@ -4272,7 +4713,6 @@ class AArch64_relocate_functions
typedef Relocate_info<size, big_endian> The_relocate_info;
typedef AArch64_relobj<size, big_endian> The_aarch64_relobj;
typedef Reloc_stub<size, big_endian> The_reloc_stub;
- typedef typename The_reloc_stub::Stub_type The_reloc_stub_type;
typedef Stub_table<size, big_endian> The_stub_table;
typedef elfcpp::Rela<size, big_endian> The_rela;
typedef typename elfcpp::Swap<size, big_endian>::Valtype AArch64_valtype;
@@ -4405,6 +4845,15 @@ class AArch64_relocate_functions
public:
+ // Construct a B insn. Note, although we group it here with other relocation
+ // operation, there is actually no 'relocation' involved here.
+ static inline void
+ construct_b(unsigned char* view, unsigned int branch_offset)
+ {
+ update_view_two_parts<32>(view, 0x05, (branch_offset >> 2),
+ 26, 0, 0xffffffff);
+ }
+
// Do a simple rela relocation at unaligned addresses.
template<int valsize>
@@ -4650,9 +5099,9 @@ maybe_apply_stub(unsigned int r_type,
typename elfcpp::Elf_types<size>::Elf_Swxword addend = rela.get_r_addend();
Address branch_target = psymval->value(object, 0) + addend;
- The_reloc_stub_type stub_type = The_reloc_stub::
- stub_type_for_reloc(r_type, address, branch_target);
- if (stub_type == The_reloc_stub::ST_NONE)
+ int stub_type =
+ The_reloc_stub::stub_type_for_reloc(r_type, address, branch_target);
+ if (stub_type == ST_NONE)
return false;
const The_aarch64_relobj* aarch64_relobj =
@@ -7258,9 +7707,15 @@ Target_aarch64<size, big_endian>::scan_erratum_843419_span(
{
Insntype insn2 = ip[1];
Insntype insn3 = ip[2];
+ Insntype erratum_insn;
+ unsigned insn_offset;
bool do_report = false;
if (is_erratum_843419_sequence(insn1, insn2, insn3))
- do_report = true;
+ {
+ do_report = true;
+ erratum_insn = insn3;
+ insn_offset = 2 * Insn_utilities::BYTES_PER_INSN;
+ }
else if (offset + 4 * Insn_utilities::BYTES_PER_INSN <= span_length)
{
// Optionally we can have an insn between ins2 and ins3
@@ -7277,15 +7732,41 @@ Target_aarch64<size, big_endian>::scan_erratum_843419_span(
Insntype insn4 = ip[3];
if (is_erratum_843419_sequence(insn1, insn2, insn4))
- do_report = true;
+ {
+ do_report = true;
+ erratum_insn = insn4;
+ insn_offset = 3 * Insn_utilities::BYTES_PER_INSN;
+ }
}
}
if (do_report)
{
- gold_error(_("Erratum 943419 found at \"%s\", section %d, "
- "offset 0x%08x."),
- relobj->name().c_str(), shndx,
- (unsigned int)(span_start + offset));
+ gold_warning(_("Erratum 843419 found and fixed at \"%s\", "
+ "section %d, offset 0x%08x."),
+ relobj->name().c_str(), shndx,
+ (unsigned int)(span_start + offset));
+ unsigned int errata_insn_offset =
+ span_start + offset + insn_offset;
+ The_stub_table* stub_table = relobj->stub_table(shndx);
+ gold_assert(stub_table != NULL);
+ if (stub_table->find_erratum_stub(relobj,
+ shndx,
+ errata_insn_offset) == NULL)
+ {
+ The_erratum_stub* stub = new The_erratum_stub(
+ relobj, ST_E_843419, shndx,
+ errata_insn_offset);
+ Address erratum_address =
+ output_address + offset + insn_offset;
+ // Stub destination address is the next insn after the
+ // erratum.
+ Address dest_address = erratum_address
+ + Insn_utilities::BYTES_PER_INSN;
+ stub->set_erratum_insn(erratum_insn);
+ stub->set_erratum_address(erratum_address);
+ stub->set_destination_address(dest_address);
+ stub_table->add_erratum_stub(stub);
+ }
}
}
@@ -7297,7 +7778,7 @@ Target_aarch64<size, big_endian>::scan_erratum_843419_span(
else // (page_offset == 0xffc), we move to next page's 0xff8.
offset += 0xffc;
}
-}
+} // End of "Target_aarch64::scan_erratum_843419_span".
// The selector for aarch64 object files.
diff --git a/gold/aarch64.cc b/gold/aarch64.cc
index aa1558f..130fcc2 100644
--- a/gold/aarch64.cc
+++ b/gold/aarch64.cc
@@ -581,71 +581,42 @@ template<int size, bool big_endian>
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
+// Stub type enum constants.
+
+enum
{
- enum
- {
- ST_NONE = 0,
+ 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 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-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,
+ // 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,
+ // 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();
+ // Number of total stub types.
+ ST_NUMBER = 5
};
-// Class that wraps insns for a particular stub. All stub templates are
+// Struct that wraps insns for a particular stub. All stub templates are
// created/initialized as constants by Stub_template_repertoire.
template<bool big_endian>
-class Stub_template
+struct Stub_template
{
-public:
- typedef typename AArch64_insn_utilities<big_endian>::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".
+ const typename AArch64_insn_utilities<big_endian>::Insntype* insns;
+ const int insn_num;
+};
// Simple singleton class that creates/initializes/stores all types of stub
@@ -657,31 +628,26 @@ class Stub_template_repertoire
public:
typedef typename AArch64_insn_utilities<big_endian>::Insntype Insntype;
- // Get singleton instance.
- static Stub_template_repertoire<big_endian>*
- get_instance()
- {
- static Stub_template_repertoire<big_endian> singleton;
- return &singleton;
- }
-
- // Get stub template for a given stub type.
- Stub_template<big_endian>*
+ // Single static method to get stub template for a given stub type.
+ static const Stub_template<big_endian>*
get_stub_template(int type)
- { return this->stub_templates_[type]; }
+ {
+ static Stub_template_repertoire<big_endian> singleton;
+ return singleton.stub_templates_[type];
+ }
private:
- // Constructor - creates/initilizes all stub templates.
+ // Constructor - creates/initializes all stub templates.
Stub_template_repertoire();
+ ~Stub_template_repertoire()
+ { }
- // Destructor - deletes all stub templates.
- ~Stub_template_repertoire();
-
+ // Disallowing copy ctor and copy assignment operator.
Stub_template_repertoire(Stub_template_repertoire&);
- Stub_template_repertoire& operator = (Stub_template_repertoire&);
+ Stub_template_repertoire& operator=(Stub_template_repertoire&);
// Data that stores all insn templates.
- Stub_template<big_endian>* stub_templates_[Stub_type::ST_NUMBER];
+ const Stub_template<big_endian>* stub_templates_[ST_NUMBER];
}; // End of "class Stub_template_repertoire".
@@ -730,8 +696,9 @@ Stub_template_repertoire<big_endian>::Stub_template_repertoire()
};
#define install_insn_template(T) \
- this->stub_templates_[Stub_type::T] = new Stub_template<big_endian>( \
- T##_INSNS, sizeof(T##_INSNS) / sizeof(T##_INSNS[0]))
+ const static Stub_template<big_endian> template_##T = { \
+ T##_INSNS, sizeof(T##_INSNS) / sizeof(T##_INSNS[0]) }; \
+ this->stub_templates_[T] = &template_##T
install_insn_template(ST_NONE);
install_insn_template(ST_ADRP_BRANCH);
@@ -743,16 +710,6 @@ Stub_template_repertoire<big_endian>::Stub_template_repertoire()
}
-// Destructor that deletes all stub templates.
-
-template<bool big_endian>
-Stub_template_repertoire<big_endian>::~Stub_template_repertoire()
-{
- for (int i = 0; i < Stub_type::ST_NUMBER; ++i)
- delete stub_templates_[i];
-}
-
-
// Base class for stubs.
template<int size, bool big_endian>
@@ -771,10 +728,7 @@ public:
Stub_base(int type)
: destination_address_(invalid_address),
offset_(invalid_offset),
- type_(type),
- // Initialize a stub template by stub type from stub repertoire.
- stub_template_(Stub_template_repertoire<big_endian>::
- get_instance()->get_stub_template(type))
+ type_(type)
{}
~Stub_base()
@@ -785,6 +739,14 @@ public:
type() const
{ return this->type_; }
+ // Get stub template that provides stub insn information.
+ const Stub_template<big_endian>*
+ stub_template() const
+ {
+ return Stub_template_repertoire<big_endian>::
+ get_stub_template(this->type());
+ }
+
// Get destination address.
AArch64_address
destination_address() const
@@ -824,12 +786,12 @@ public:
// Return the stub insn.
const Insntype*
insns() const
- { return this->stub_template_->insns(); }
+ { return this->stub_template()->insns; }
// Return num of stub insns.
unsigned int
insn_num() const
- { return this->stub_template_->insn_num(); }
+ { return this->stub_template()->insn_num; }
// Get size of the stub.
int
@@ -855,20 +817,20 @@ private:
AArch64_address destination_address_;
// The stub offset. Note this has difference interpretations between an
// Reloc_stub and an Erratum_stub. For Reloc_stub this is the offset from the
- // beginning of the containng stub_table, whereas for Erratum_stub, this is
+ // beginning of the containing stub_table, whereas for Erratum_stub, this is
// the offset from the end of reloc_stubs.
section_offset_type offset_;
// Stub type.
const int type_;
- // Stub template that provides stub insn information.
- const Stub_template<big_endian>* stub_template_;
}; // End of "Stub_base".
// Erratum stub class. An erratum stub differs from a reloc stub in that for
-// each erratum occurrence, we generates an erratum stub, we never share erratum
+// each erratum occurrence, we generate an erratum stub. We never share erratum
// stubs, whereas for reloc stubs, different branches insns share a single reloc
-// stub as long as the branch targets are the same.
+// 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.)
template<int size, bool big_endian>
class Erratum_stub : public Stub_base<size, big_endian>
@@ -991,7 +953,7 @@ Erratum_stub<size, big_endian>::do_write(unsigned char* view, section_size_type)
Insntype* ip = reinterpret_cast<Insntype*>(view);
// For current implemnted erratum 843419, (and 835769 which is to be
// implemented soon), the first insn in the stub is always a copy of the
- // problmatic insn (in 843419, the mem access insn), followed by a jump-back.
+ // problematic insn (in 843419, the mem access insn), followed by a jump-back.
elfcpp::Swap<32, big_endian>::writeval(ip, this->erratum_insn());
for (uint32_t i = 1; i < num_insns; ++i)
elfcpp::Swap<32, big_endian>::writeval(ip + i, insns[i]);
@@ -1201,16 +1163,16 @@ Reloc_stub<size, big_endian>::stub_type_for_reloc(
}
if (aarch64_valid_branch_offset_p(branch_offset))
- return Stub_type::ST_NONE;
+ return ST_NONE;
if (aarch64_valid_for_adrp_p(location, dest))
- return Stub_type::ST_ADRP_BRANCH;
+ return ST_ADRP_BRANCH;
if (parameters->options().output_is_position_independent()
&& parameters->options().output_is_executable())
- return Stub_type::ST_LONG_BRANCH_PCREL;
+ return ST_LONG_BRANCH_PCREL;
- return Stub_type::ST_LONG_BRANCH_ABS;
+ return ST_LONG_BRANCH_ABS;
}
// A class to hold stubs for the ARM target.
@@ -1403,7 +1365,7 @@ Stub_table<size, big_endian>::find_erratum_stub(
The_aarch64_relobj* a64relobj, unsigned int shndx, unsigned int sh_offset)
{
// A dummy object used as key to search in the set.
- The_erratum_stub key(a64relobj, Stub_type::ST_NONE,
+ The_erratum_stub key(a64relobj, ST_NONE,
shndx, sh_offset);
Erratum_stub_set_iter i = this->erratum_stubs_.find(&key);
if (i != this->erratum_stubs_.end())
@@ -1416,7 +1378,7 @@ Stub_table<size, big_endian>::find_erratum_stub(
}
-// Find all the errata for a given input sectin. The return value is a pair of
+// Find all the errata for a given input section. The return value is a pair of
// iterators [begin, end).
template<int size, bool big_endian>
@@ -1427,7 +1389,7 @@ Stub_table<size, big_endian>::find_erratum_stubs_for_input_section(
{
typedef std::pair<Erratum_stub_set_iter, Erratum_stub_set_iter> Result_pair;
Erratum_stub_set_iter start, end;
- The_erratum_stub low_key(a64relobj, Stub_type::ST_NONE, shndx, 0);
+ The_erratum_stub low_key(a64relobj, ST_NONE, shndx, 0);
start = this->erratum_stubs_.lower_bound(&low_key);
if (start == this->erratum_stubs_.end())
return Result_pair(this->erratum_stubs_.end(),
@@ -1480,6 +1442,9 @@ relocate_stubs(const The_relocate_info* relinfo,
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)
@@ -1491,11 +1456,10 @@ relocate_stubs(const The_relocate_info* relinfo,
int b_offset = 0;
switch ((*i)->type())
{
- case Stub_type::ST_E_843419:
+ case ST_E_843419:
// For the erratum, the 2nd insn is a b-insn to be patched
// (relocated).
- stub_b_insn_address = stub_address
- + 1 * AArch64_insn_utilities<big_endian>::BYTES_PER_INSN;
+ 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()),
@@ -3507,7 +3471,7 @@ Target_aarch64<size, big_endian>::scan_reloc_for_stub(
int stub_type = The_reloc_stub::
stub_type_for_reloc(r_type, address, destination);
- if (stub_type == Stub_type::ST_NONE)
+ if (stub_type == ST_NONE)
return;
The_stub_table* stub_table = aarch64_relobj->stub_table(relinfo->data_shndx);
@@ -3774,7 +3738,7 @@ relocate_stub(The_reloc_stub* stub,
switch(stub->type())
{
- case Stub_type::ST_ADRP_BRANCH:
+ case ST_ADRP_BRANCH:
{
// 1st reloc is ADR_PREL_PG_HI21
The_reloc_functions_status status =
@@ -3795,12 +3759,12 @@ relocate_stub(The_reloc_stub* stub,
}
break;
- case Stub_type::ST_LONG_BRANCH_ABS:
+ case ST_LONG_BRANCH_ABS:
// 1st reloc is R_AARCH64_PREL64, at offset 8
elfcpp::Swap<64,big_endian>::writeval(view + 8, dest);
break;
- case Stub_type::ST_LONG_BRANCH_PCREL:
+ case ST_LONG_BRANCH_PCREL:
{
// "PC" calculation is the 2nd insn in the stub.
uint64_t offset = dest - (address + 4);
@@ -5137,7 +5101,7 @@ maybe_apply_stub(unsigned int r_type,
Address branch_target = psymval->value(object, 0) + addend;
int stub_type =
The_reloc_stub::stub_type_for_reloc(r_type, address, branch_target);
- if (stub_type == Stub_type::ST_NONE)
+ if (stub_type == ST_NONE)
return false;
const The_aarch64_relobj* aarch64_relobj =
@@ -7790,7 +7754,7 @@ Target_aarch64<size, big_endian>::scan_erratum_843419_span(
errata_insn_offset) == NULL)
{
The_erratum_stub* stub = new The_erratum_stub(
- relobj, Stub_type::ST_E_843419, shndx,
+ relobj, ST_E_843419, shndx,
errata_insn_offset);
Address erratum_address =
output_address + offset + insn_offset;