| // arm-reloc-property.h -- ARM relocation properties -*- C++ -*- |
| |
| // Copyright (C) 2010-2024 Free Software Foundation, Inc. |
| // Written by Doug Kwan <dougkwan@google.com>. |
| |
| // This file is part of gold. |
| |
| // This program is free software; you can redistribute it and/or modify |
| // it under the terms of the GNU General Public License as published by |
| // the Free Software Foundation; either version 3 of the License, or |
| // (at your option) any later version. |
| |
| // This program is distributed in the hope that it will be useful, |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| // GNU General Public License for more details. |
| |
| // You should have received a copy of the GNU General Public License |
| // along with this program; if not, write to the Free Software |
| // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
| // MA 02110-1301, USA. |
| |
| #ifndef GOLD_ARM_RELOC_PROPERTY_H |
| #define GOLD_ARM_RELOC_PROPERTY_H |
| |
| namespace gold |
| { |
| // The Arm_reloc_property class is to store information about a particular |
| // relocation code. |
| |
| class Arm_reloc_property |
| { |
| public: |
| // Types of relocation codes. |
| enum Reloc_type { |
| RT_NONE, // No relocation type. |
| RT_STATIC, // Relocations processed by static linkers. |
| RT_DYNAMIC, // Relocations processed by dynamic linkers. |
| RT_PRIVATE, // Private relocations, not supported by gold. |
| RT_OBSOLETE // Obsolete relocations that should not be used. |
| }; |
| |
| // Classes of relocation codes. |
| enum Reloc_class { |
| RC_NONE, // No relocation class. |
| RC_DATA, // Data relocation. |
| RC_ARM, // ARM instruction relocation. |
| RC_THM16, // 16-bit THUMB instruction relocation. |
| RC_THM32, // 32-bit THUMB instruction relocation. |
| RC_MISC // Miscellaneous class. |
| }; |
| |
| // Types of bases of relative addressing relocation codes. |
| enum Relative_address_base { |
| RAB_NONE, // Relocation is not relative addressing |
| RAB_B_S, // Address origin of output segment of defining symbol. |
| RAB_DELTA_B_S, // Change of address origin. |
| RAB_GOT_ORG, // Origin of GOT. |
| RAB_P, // Address of the place being relocated. |
| RAB_Pa, // Adjusted address (P & 0xfffffffc). |
| RAB_TLS, // Thread local storage. |
| RAB_tp // Thread pointer. |
| }; |
| |
| // Relocation code represented by this. |
| unsigned int |
| code() const |
| { return this->code_; } |
| |
| // Name of the relocation code. |
| const std::string& |
| name() const |
| { return this->name_; } |
| |
| // Type of relocation code. |
| Reloc_type |
| reloc_type() const |
| { return this->reloc_type_; } |
| |
| // Whether this code is deprecated. |
| bool |
| is_deprecated() const |
| { return this->is_deprecated_; } |
| |
| // Class of relocation code. |
| Reloc_class |
| reloc_class() const |
| { return this->reloc_class_; } |
| |
| // Whether this code is implemented in gold. |
| bool |
| is_implemented() const |
| { return this->is_implemented_; } |
| |
| // If code is a group relocation code, return the group number, otherwise -1. |
| int |
| group_index() const |
| { return this->group_index_; } |
| |
| // Whether relocation checks for overflow. |
| bool |
| checks_overflow() const |
| { return this->checks_overflow_; } |
| |
| // Return size of relocation. |
| size_t |
| size() const |
| { return this->size_; } |
| |
| // Return alignment of relocation. |
| size_t |
| align() const |
| { return this->align_; } |
| |
| // Whether relocation use a GOT entry. |
| bool |
| uses_got_entry() const |
| { return this->uses_got_entry_; } |
| |
| // Whether relocation use a GOT origin. |
| bool |
| uses_got_origin() const |
| { return this->uses_got_origin_; } |
| |
| // Whether relocation uses the Thumb-bit in a symbol address. |
| bool |
| uses_thumb_bit() const |
| { return this->uses_thumb_bit_; } |
| |
| // Whether relocation uses the symbol base. |
| bool |
| uses_symbol_base() const |
| { return this->uses_symbol_base_; } |
| |
| // Whether relocation uses the symbol. |
| bool |
| uses_symbol() const |
| { return this->uses_symbol_; } |
| |
| // Return the type of relative address base or RAB_NONE if this |
| // is not a relative addressing relocation. |
| Relative_address_base |
| relative_address_base() const |
| { return this->relative_address_base_; } |
| |
| protected: |
| // These are protected. We only allow Arm_reloc_property_table to |
| // manage Arm_reloc_property. |
| Arm_reloc_property(unsigned int code, const char* name, Reloc_type rtype, |
| bool is_deprecated, Reloc_class rclass, |
| const std::string& operation, bool is_implemented, |
| int group_index, bool checks_overflow); |
| |
| friend class Arm_reloc_property_table; |
| |
| private: |
| // Copying is not allowed. |
| Arm_reloc_property(const Arm_reloc_property&); |
| Arm_reloc_property& operator=(const Arm_reloc_property&); |
| |
| // The Tree_node class is used to represent parsed relocation operations. |
| // We look at Trees to extract information about relocation operations. |
| class Tree_node |
| { |
| public: |
| typedef std::vector<Tree_node*> Tree_node_vector; |
| |
| // Construct a leaf node. |
| Tree_node(const char* name) |
| : is_leaf_(true), name_(name), children_() |
| { } |
| |
| // Construct an internal node. A node owns all its children and is |
| // responsible for releasing them at its own destruction. |
| Tree_node(Tree_node_vector::const_iterator begin, |
| Tree_node_vector::const_iterator end) |
| : is_leaf_(false), name_(), children_() |
| { |
| for (Tree_node_vector::const_iterator p = begin; p != end; ++p) |
| this->children_.push_back(*p); |
| } |
| |
| ~Tree_node() |
| { |
| for(size_t i = 0; i <this->children_.size(); ++i) |
| delete this->children_[i]; |
| } |
| |
| // Whether this is a leaf node. |
| bool |
| is_leaf() const |
| { return this->is_leaf_; } |
| |
| // Return name of this. This is only valid for a leaf node. |
| const std::string& |
| name() const |
| { |
| gold_assert(this->is_leaf_); |
| return this->name_; |
| } |
| |
| // Return the number of children. This is only valid for a non-leaf node. |
| size_t |
| number_of_children() const |
| { |
| gold_assert(!this->is_leaf_); |
| return this->children_.size(); |
| } |
| |
| // Return the i-th child of this. This is only valid for a non-leaf node. |
| Tree_node* |
| child(size_t i) const |
| { |
| gold_assert(!this->is_leaf_ && i < this->children_.size()); |
| return this->children_[i]; |
| } |
| |
| // Parse an S-expression string and build a tree and return the root node. |
| // Caller is responsible for releasing tree after use. |
| static Tree_node* |
| make_tree(const std::string&); |
| |
| // Convert a tree back to an S-expression string. |
| std::string |
| s_expression() const |
| { |
| if (this->is_leaf_) |
| return this->name_; |
| |
| // Concatenate S-expressions of children. Enclose them with |
| // a pair of parentheses and use space as token delimiters. |
| std::string s("("); |
| for(size_t i = 0; i <this->children_.size(); ++i) |
| s = s + " " + this->children_[i]->s_expression(); |
| return s + " )"; |
| } |
| |
| private: |
| // Whether this is a leaf node. |
| bool is_leaf_; |
| // Name of this if this is a leaf node. |
| std::string name_; |
| // Children of this if this a non-leaf node. |
| Tree_node_vector children_; |
| }; |
| |
| // Relocation code. |
| unsigned int code_; |
| // Relocation name. |
| std::string name_; |
| // Type of relocation. |
| Reloc_type reloc_type_; |
| // Class of relocation. |
| Reloc_class reloc_class_; |
| // Group index (0, 1, or 2) if this is a group relocation or -1 otherwise. |
| int group_index_; |
| // Size of relocation. |
| size_t size_; |
| // Alignment of relocation. |
| size_t align_; |
| // Relative address base. |
| Relative_address_base relative_address_base_; |
| // Whether this is deprecated. |
| bool is_deprecated_ : 1; |
| // Whether this is implemented in gold. |
| bool is_implemented_ : 1; |
| // Whether this checks overflow. |
| bool checks_overflow_ : 1; |
| // Whether this uses a GOT entry. |
| bool uses_got_entry_ : 1; |
| // Whether this uses a GOT origin. |
| bool uses_got_origin_ : 1; |
| // Whether this uses a PLT entry. |
| bool uses_plt_entry_ : 1; |
| // Whether this uses the THUMB bit in symbol address. |
| bool uses_thumb_bit_ : 1; |
| // Whether this uses the symbol base. |
| bool uses_symbol_base_ : 1; |
| // Whether this uses an addend. |
| bool uses_addend_ : 1; |
| // Whether this uses the symbol. |
| bool uses_symbol_ : 1; |
| }; |
| |
| // Arm_reloc_property_table. This table is used for looking up properties |
| // of relocation types. The table entries are initialized using information |
| // from arm-reloc.def. |
| |
| class Arm_reloc_property_table |
| { |
| public: |
| Arm_reloc_property_table(); |
| |
| // Return an Arm_reloc_property object for CODE if it is a valid relocation |
| // code or NULL otherwise. |
| const Arm_reloc_property* |
| get_reloc_property(unsigned int code) const |
| { |
| gold_assert(code < Property_table_size); |
| return this->table_[code]; |
| } |
| |
| // Like get_reloc_property but only return non-NULL if relocation code is |
| // static and implemented. |
| const Arm_reloc_property* |
| get_implemented_static_reloc_property(unsigned int code) const |
| { |
| gold_assert(code < Property_table_size); |
| const Arm_reloc_property* arp = this->table_[code]; |
| return ((arp != NULL |
| && (arp->reloc_type() == Arm_reloc_property::RT_STATIC) |
| && arp->is_implemented()) |
| ? arp |
| : NULL); |
| } |
| |
| // Return a string describing the relocation code that is not |
| // an implemented static reloc code. |
| std::string |
| reloc_name_in_error_message(unsigned int code); |
| |
| private: |
| // Copying is not allowed. |
| Arm_reloc_property_table(const Arm_reloc_property_table&); |
| Arm_reloc_property_table& operator=(const Arm_reloc_property_table&); |
| |
| // The Parse_expression class is used to convert relocation operations in |
| // arm-reloc.def into S-expression strings, which are parsed again to |
| // build actual expression trees. We do not build the expression trees |
| // directly because the parser for operations in arm-reloc.def is simpler |
| // this way. Conversion from S-expressions to trees is simple. |
| class Parse_expression |
| { |
| public: |
| // Construction a Parse_expression with an S-expression string. |
| Parse_expression(const std::string& s_expression) |
| : s_expression_(s_expression) |
| { } |
| |
| // Value of this expression as an S-expression string. |
| const std::string& |
| s_expression() const |
| { return this->s_expression_; } |
| |
| // We want to overload operators used in relocation operations so |
| // that we can execute operations in arm-reloc.def to generate |
| // S-expressions directly. |
| #define DEF_OPERATOR_OVERLOAD(op) \ |
| Parse_expression \ |
| operator op (const Parse_expression& e) \ |
| { \ |
| return Parse_expression("( " #op " " + this->s_expression_ + " " + \ |
| e.s_expression_ + " )"); \ |
| } |
| |
| // Operator appearing in relocation operations in arm-reloc.def. |
| DEF_OPERATOR_OVERLOAD(+) |
| DEF_OPERATOR_OVERLOAD(-) |
| DEF_OPERATOR_OVERLOAD(|) |
| |
| private: |
| // This represented as an S-expression string. |
| std::string s_expression_; |
| }; |
| |
| #define DEF_RELOC_FUNC(name) \ |
| static Parse_expression \ |
| (name)(const Parse_expression& arg) \ |
| { return Parse_expression("( " #name " " + arg.s_expression() + " )"); } |
| |
| // Functions appearing in relocation operations in arm-reloc.def. |
| DEF_RELOC_FUNC(B) |
| DEF_RELOC_FUNC(DELTA_B) |
| DEF_RELOC_FUNC(GOT) |
| DEF_RELOC_FUNC(Module) |
| DEF_RELOC_FUNC(PLT) |
| |
| static const unsigned int Property_table_size = 256; |
| |
| // The property table. |
| Arm_reloc_property* table_[Property_table_size]; |
| }; |
| |
| } // End namespace gold. |
| |
| #endif // !defined(GOLD_ARM_RELOC_PROPERTY_H) |