| 1 | // arm-reloc-property.h -- ARM relocation properties -*- C++ -*- |
| 2 | |
| 3 | // Copyright (C) 2010-2019 Free Software Foundation, Inc. |
| 4 | // Written by Doug Kwan <dougkwan@google.com>. |
| 5 | |
| 6 | // This file is part of gold. |
| 7 | |
| 8 | // This program is free software; you can redistribute it and/or modify |
| 9 | // it under the terms of the GNU General Public License as published by |
| 10 | // the Free Software Foundation; either version 3 of the License, or |
| 11 | // (at your option) any later version. |
| 12 | |
| 13 | // This program is distributed in the hope that it will be useful, |
| 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | // GNU General Public License for more details. |
| 17 | |
| 18 | // You should have received a copy of the GNU General Public License |
| 19 | // along with this program; if not, write to the Free Software |
| 20 | // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
| 21 | // MA 02110-1301, USA. |
| 22 | |
| 23 | #ifndef GOLD_ARM_RELOC_PROPERTY_H |
| 24 | #define GOLD_ARM_RELOC_PROPERTY_H |
| 25 | |
| 26 | namespace gold |
| 27 | { |
| 28 | // The Arm_reloc_property class is to store information about a particular |
| 29 | // relocation code. |
| 30 | |
| 31 | class Arm_reloc_property |
| 32 | { |
| 33 | public: |
| 34 | // Types of relocation codes. |
| 35 | enum Reloc_type { |
| 36 | RT_NONE, // No relocation type. |
| 37 | RT_STATIC, // Relocations processed by static linkers. |
| 38 | RT_DYNAMIC, // Relocations processed by dynamic linkers. |
| 39 | RT_PRIVATE, // Private relocations, not supported by gold. |
| 40 | RT_OBSOLETE // Obsolete relocations that should not be used. |
| 41 | }; |
| 42 | |
| 43 | // Classes of relocation codes. |
| 44 | enum Reloc_class { |
| 45 | RC_NONE, // No relocation class. |
| 46 | RC_DATA, // Data relocation. |
| 47 | RC_ARM, // ARM instruction relocation. |
| 48 | RC_THM16, // 16-bit THUMB instruction relocation. |
| 49 | RC_THM32, // 32-bit THUMB instruction relocation. |
| 50 | RC_MISC // Miscellaneous class. |
| 51 | }; |
| 52 | |
| 53 | // Types of bases of relative addressing relocation codes. |
| 54 | enum Relative_address_base { |
| 55 | RAB_NONE, // Relocation is not relative addressing |
| 56 | RAB_B_S, // Address origin of output segment of defining symbol. |
| 57 | RAB_DELTA_B_S, // Change of address origin. |
| 58 | RAB_GOT_ORG, // Origin of GOT. |
| 59 | RAB_P, // Address of the place being relocated. |
| 60 | RAB_Pa, // Adjusted address (P & 0xfffffffc). |
| 61 | RAB_TLS, // Thread local storage. |
| 62 | RAB_tp // Thread pointer. |
| 63 | }; |
| 64 | |
| 65 | // Relocation code represented by this. |
| 66 | unsigned int |
| 67 | code() const |
| 68 | { return this->code_; } |
| 69 | |
| 70 | // Name of the relocation code. |
| 71 | const std::string& |
| 72 | name() const |
| 73 | { return this->name_; } |
| 74 | |
| 75 | // Type of relocation code. |
| 76 | Reloc_type |
| 77 | reloc_type() const |
| 78 | { return this->reloc_type_; } |
| 79 | |
| 80 | // Whether this code is deprecated. |
| 81 | bool |
| 82 | is_deprecated() const |
| 83 | { return this->is_deprecated_; } |
| 84 | |
| 85 | // Class of relocation code. |
| 86 | Reloc_class |
| 87 | reloc_class() const |
| 88 | { return this->reloc_class_; } |
| 89 | |
| 90 | // Whether this code is implemented in gold. |
| 91 | bool |
| 92 | is_implemented() const |
| 93 | { return this->is_implemented_; } |
| 94 | |
| 95 | // If code is a group relocation code, return the group number, otherwise -1. |
| 96 | int |
| 97 | group_index() const |
| 98 | { return this->group_index_; } |
| 99 | |
| 100 | // Whether relocation checks for overflow. |
| 101 | bool |
| 102 | checks_overflow() const |
| 103 | { return this->checks_overflow_; } |
| 104 | |
| 105 | // Return size of relocation. |
| 106 | size_t |
| 107 | size() const |
| 108 | { return this->size_; } |
| 109 | |
| 110 | // Return alignment of relocation. |
| 111 | size_t |
| 112 | align() const |
| 113 | { return this->align_; } |
| 114 | |
| 115 | // Whether relocation use a GOT entry. |
| 116 | bool |
| 117 | uses_got_entry() const |
| 118 | { return this->uses_got_entry_; } |
| 119 | |
| 120 | // Whether relocation use a GOT origin. |
| 121 | bool |
| 122 | uses_got_origin() const |
| 123 | { return this->uses_got_origin_; } |
| 124 | |
| 125 | // Whether relocation uses the Thumb-bit in a symbol address. |
| 126 | bool |
| 127 | uses_thumb_bit() const |
| 128 | { return this->uses_thumb_bit_; } |
| 129 | |
| 130 | // Whether relocation uses the symbol base. |
| 131 | bool |
| 132 | uses_symbol_base() const |
| 133 | { return this->uses_symbol_base_; } |
| 134 | |
| 135 | // Whether relocation uses the symbol. |
| 136 | bool |
| 137 | uses_symbol() const |
| 138 | { return this->uses_symbol_; } |
| 139 | |
| 140 | // Return the type of relative address base or RAB_NONE if this |
| 141 | // is not a relative addressing relocation. |
| 142 | Relative_address_base |
| 143 | relative_address_base() const |
| 144 | { return this->relative_address_base_; } |
| 145 | |
| 146 | protected: |
| 147 | // These are protected. We only allow Arm_reloc_property_table to |
| 148 | // manage Arm_reloc_property. |
| 149 | Arm_reloc_property(unsigned int code, const char* name, Reloc_type rtype, |
| 150 | bool is_deprecated, Reloc_class rclass, |
| 151 | const std::string& operation, bool is_implemented, |
| 152 | int group_index, bool checks_overflow); |
| 153 | |
| 154 | friend class Arm_reloc_property_table; |
| 155 | |
| 156 | private: |
| 157 | // Copying is not allowed. |
| 158 | Arm_reloc_property(const Arm_reloc_property&); |
| 159 | Arm_reloc_property& operator=(const Arm_reloc_property&); |
| 160 | |
| 161 | // The Tree_node class is used to represent parsed relocation operations. |
| 162 | // We look at Trees to extract information about relocation operations. |
| 163 | class Tree_node |
| 164 | { |
| 165 | public: |
| 166 | typedef std::vector<Tree_node*> Tree_node_vector; |
| 167 | |
| 168 | // Construct a leaf node. |
| 169 | Tree_node(const char* name) |
| 170 | : is_leaf_(true), name_(name), children_() |
| 171 | { } |
| 172 | |
| 173 | // Construct an internal node. A node owns all its children and is |
| 174 | // responsible for releasing them at its own destruction. |
| 175 | Tree_node(Tree_node_vector::const_iterator begin, |
| 176 | Tree_node_vector::const_iterator end) |
| 177 | : is_leaf_(false), name_(), children_() |
| 178 | { |
| 179 | for (Tree_node_vector::const_iterator p = begin; p != end; ++p) |
| 180 | this->children_.push_back(*p); |
| 181 | } |
| 182 | |
| 183 | ~Tree_node() |
| 184 | { |
| 185 | for(size_t i = 0; i <this->children_.size(); ++i) |
| 186 | delete this->children_[i]; |
| 187 | } |
| 188 | |
| 189 | // Whether this is a leaf node. |
| 190 | bool |
| 191 | is_leaf() const |
| 192 | { return this->is_leaf_; } |
| 193 | |
| 194 | // Return name of this. This is only valid for a leaf node. |
| 195 | const std::string& |
| 196 | name() const |
| 197 | { |
| 198 | gold_assert(this->is_leaf_); |
| 199 | return this->name_; |
| 200 | } |
| 201 | |
| 202 | // Return the number of children. This is only valid for a non-leaf node. |
| 203 | size_t |
| 204 | number_of_children() const |
| 205 | { |
| 206 | gold_assert(!this->is_leaf_); |
| 207 | return this->children_.size(); |
| 208 | } |
| 209 | |
| 210 | // Return the i-th child of this. This is only valid for a non-leaf node. |
| 211 | Tree_node* |
| 212 | child(size_t i) const |
| 213 | { |
| 214 | gold_assert(!this->is_leaf_ && i < this->children_.size()); |
| 215 | return this->children_[i]; |
| 216 | } |
| 217 | |
| 218 | // Parse an S-expression string and build a tree and return the root node. |
| 219 | // Caller is responsible for releasing tree after use. |
| 220 | static Tree_node* |
| 221 | make_tree(const std::string&); |
| 222 | |
| 223 | // Convert a tree back to an S-expression string. |
| 224 | std::string |
| 225 | s_expression() const |
| 226 | { |
| 227 | if (this->is_leaf_) |
| 228 | return this->name_; |
| 229 | |
| 230 | // Concatenate S-expressions of children. Enclose them with |
| 231 | // a pair of parentheses and use space as token delimiters. |
| 232 | std::string s("("); |
| 233 | for(size_t i = 0; i <this->children_.size(); ++i) |
| 234 | s = s + " " + this->children_[i]->s_expression(); |
| 235 | return s + " )"; |
| 236 | } |
| 237 | |
| 238 | private: |
| 239 | // Whether this is a leaf node. |
| 240 | bool is_leaf_; |
| 241 | // Name of this if this is a leaf node. |
| 242 | std::string name_; |
| 243 | // Children of this if this a non-leaf node. |
| 244 | Tree_node_vector children_; |
| 245 | }; |
| 246 | |
| 247 | // Relocation code. |
| 248 | unsigned int code_; |
| 249 | // Relocation name. |
| 250 | std::string name_; |
| 251 | // Type of relocation. |
| 252 | Reloc_type reloc_type_; |
| 253 | // Class of relocation. |
| 254 | Reloc_class reloc_class_; |
| 255 | // Group index (0, 1, or 2) if this is a group relocation or -1 otherwise. |
| 256 | int group_index_; |
| 257 | // Size of relocation. |
| 258 | size_t size_; |
| 259 | // Alignment of relocation. |
| 260 | size_t align_; |
| 261 | // Relative address base. |
| 262 | Relative_address_base relative_address_base_; |
| 263 | // Whether this is deprecated. |
| 264 | bool is_deprecated_ : 1; |
| 265 | // Whether this is implemented in gold. |
| 266 | bool is_implemented_ : 1; |
| 267 | // Whether this checks overflow. |
| 268 | bool checks_overflow_ : 1; |
| 269 | // Whether this uses a GOT entry. |
| 270 | bool uses_got_entry_ : 1; |
| 271 | // Whether this uses a GOT origin. |
| 272 | bool uses_got_origin_ : 1; |
| 273 | // Whether this uses a PLT entry. |
| 274 | bool uses_plt_entry_ : 1; |
| 275 | // Whether this uses the THUMB bit in symbol address. |
| 276 | bool uses_thumb_bit_ : 1; |
| 277 | // Whether this uses the symbol base. |
| 278 | bool uses_symbol_base_ : 1; |
| 279 | // Whether this uses an addend. |
| 280 | bool uses_addend_ : 1; |
| 281 | // Whether this uses the symbol. |
| 282 | bool uses_symbol_ : 1; |
| 283 | }; |
| 284 | |
| 285 | // Arm_reloc_property_table. This table is used for looking up properties |
| 286 | // of relocation types. The table entries are initialized using information |
| 287 | // from arm-reloc.def. |
| 288 | |
| 289 | class Arm_reloc_property_table |
| 290 | { |
| 291 | public: |
| 292 | Arm_reloc_property_table(); |
| 293 | |
| 294 | // Return an Arm_reloc_property object for CODE if it is a valid relocation |
| 295 | // code or NULL otherwise. |
| 296 | const Arm_reloc_property* |
| 297 | get_reloc_property(unsigned int code) const |
| 298 | { |
| 299 | gold_assert(code < Property_table_size); |
| 300 | return this->table_[code]; |
| 301 | } |
| 302 | |
| 303 | // Like get_reloc_property but only return non-NULL if relocation code is |
| 304 | // static and implemented. |
| 305 | const Arm_reloc_property* |
| 306 | get_implemented_static_reloc_property(unsigned int code) const |
| 307 | { |
| 308 | gold_assert(code < Property_table_size); |
| 309 | const Arm_reloc_property* arp = this->table_[code]; |
| 310 | return ((arp != NULL |
| 311 | && (arp->reloc_type() == Arm_reloc_property::RT_STATIC) |
| 312 | && arp->is_implemented()) |
| 313 | ? arp |
| 314 | : NULL); |
| 315 | } |
| 316 | |
| 317 | // Return a string describing the relocation code that is not |
| 318 | // an implemented static reloc code. |
| 319 | std::string |
| 320 | reloc_name_in_error_message(unsigned int code); |
| 321 | |
| 322 | private: |
| 323 | // Copying is not allowed. |
| 324 | Arm_reloc_property_table(const Arm_reloc_property_table&); |
| 325 | Arm_reloc_property_table& operator=(const Arm_reloc_property_table&); |
| 326 | |
| 327 | // The Parse_expression class is used to convert relocation operations in |
| 328 | // arm-reloc.def into S-expression strings, which are parsed again to |
| 329 | // build actual expression trees. We do not build the expression trees |
| 330 | // directly because the parser for operations in arm-reloc.def is simpler |
| 331 | // this way. Conversion from S-expressions to trees is simple. |
| 332 | class Parse_expression |
| 333 | { |
| 334 | public: |
| 335 | // Construction a Parse_expression with an S-expression string. |
| 336 | Parse_expression(const std::string& s_expression) |
| 337 | : s_expression_(s_expression) |
| 338 | { } |
| 339 | |
| 340 | // Value of this expression as an S-expression string. |
| 341 | const std::string& |
| 342 | s_expression() const |
| 343 | { return this->s_expression_; } |
| 344 | |
| 345 | // We want to overload operators used in relocation operations so |
| 346 | // that we can execute operations in arm-reloc.def to generate |
| 347 | // S-expressions directly. |
| 348 | #define DEF_OPERATOR_OVERLOAD(op) \ |
| 349 | Parse_expression \ |
| 350 | operator op (const Parse_expression& e) \ |
| 351 | { \ |
| 352 | return Parse_expression("( " #op " " + this->s_expression_ + " " + \ |
| 353 | e.s_expression_ + " )"); \ |
| 354 | } |
| 355 | |
| 356 | // Operator appearing in relocation operations in arm-reloc.def. |
| 357 | DEF_OPERATOR_OVERLOAD(+) |
| 358 | DEF_OPERATOR_OVERLOAD(-) |
| 359 | DEF_OPERATOR_OVERLOAD(|) |
| 360 | |
| 361 | private: |
| 362 | // This represented as an S-expression string. |
| 363 | std::string s_expression_; |
| 364 | }; |
| 365 | |
| 366 | #define DEF_RELOC_FUNC(name) \ |
| 367 | static Parse_expression \ |
| 368 | (name)(const Parse_expression& arg) \ |
| 369 | { return Parse_expression("( " #name " " + arg.s_expression() + " )"); } |
| 370 | |
| 371 | // Functions appearing in relocation operations in arm-reloc.def. |
| 372 | DEF_RELOC_FUNC(B) |
| 373 | DEF_RELOC_FUNC(DELTA_B) |
| 374 | DEF_RELOC_FUNC(GOT) |
| 375 | DEF_RELOC_FUNC(Module) |
| 376 | DEF_RELOC_FUNC(PLT) |
| 377 | |
| 378 | static const unsigned int Property_table_size = 256; |
| 379 | |
| 380 | // The property table. |
| 381 | Arm_reloc_property* table_[Property_table_size]; |
| 382 | }; |
| 383 | |
| 384 | } // End namespace gold. |
| 385 | |
| 386 | #endif // !defined(GOLD_ARM_RELOC_PROPERTY_H) |