1 // arm-reloc-property.cc -- ARM relocation property. 2 3 // Copyright (C) 2010-2014 Free Software Foundation, Inc. 4 // Written by Doug Kwan <dougkwan (at) 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 #include "gold.h" 24 25 #include <cstdio> 26 #include <cstring> 27 #include <stack> 28 #include <string> 29 #include <vector> 30 31 #include "elfcpp.h" 32 #include "arm.h" 33 #include "arm-reloc-property.h" 34 35 namespace gold 36 { 37 38 // Arm_reloc_property::Tree_node methods. 39 40 // Parse an S-expression S and build a tree and return the root node. 41 // Caller is responsible for releasing tree after use. 42 43 Arm_reloc_property::Tree_node* 44 Arm_reloc_property::Tree_node::make_tree(const std::string& s) 45 { 46 std::stack<size_t> size_stack; 47 Tree_node_vector node_stack; 48 49 // strtok needs a non-const string pointer. 50 char* buffer = new char[s.size() + 1]; 51 memcpy(buffer, s.data(), s.size()); 52 buffer[s.size()] = '\0'; 53 char* token = strtok(buffer, " "); 54 55 while (token != NULL) 56 { 57 if (strcmp(token, "(") == 0) 58 // Remember the node stack position for start of a new internal node. 59 size_stack.push(node_stack.size()); 60 else if (strcmp(token, ")") == 0) 61 { 62 // Pop all tree nodes after the previous '(' and use them as 63 // children to build a new internal node. Push internal node back. 64 size_t current_size = node_stack.size(); 65 size_t prev_size = size_stack.top(); 66 size_stack.pop(); 67 Tree_node* node = 68 new Tree_node(node_stack.begin() + prev_size, 69 node_stack.begin() + current_size); 70 node_stack.resize(prev_size); 71 node_stack.push_back(node); 72 } 73 else 74 // Just push a leaf node to node_stack. 75 node_stack.push_back(new Tree_node(token)); 76 77 token = strtok(NULL, " "); 78 } 79 80 delete[] buffer; 81 82 // At this point, size_stack should be empty and node_stack should only 83 // contain the root node. 84 gold_assert(size_stack.empty() && node_stack.size() == 1); 85 return node_stack[0]; 86 } 87 88 // Arm_reloc_property methods. 89 90 // Constructor. 91 92 Arm_reloc_property::Arm_reloc_property( 93 unsigned int code, 94 const char* name, 95 Reloc_type rtype, 96 bool is_deprecated, 97 Reloc_class rclass, 98 const std::string& operation, 99 bool is_implemented, 100 int group_index, 101 bool checks_overflow) 102 : code_(code), name_(name), reloc_type_(rtype), reloc_class_(rclass), 103 group_index_(group_index), size_(0), align_(1), 104 relative_address_base_(RAB_NONE), is_deprecated_(is_deprecated), 105 is_implemented_(is_implemented), checks_overflow_(checks_overflow), 106 uses_got_entry_(false), uses_got_origin_(false), uses_plt_entry_(false), 107 uses_thumb_bit_(false), uses_symbol_base_(false), uses_addend_(false), 108 uses_symbol_(false) 109 { 110 // Set size and alignment of static and dynamic relocations. 111 if (rtype == RT_STATIC) 112 { 113 switch (rclass) 114 { 115 case RC_DATA: 116 // Except for R_ARM_ABS16 and R_ARM_ABS8, all static data relocations 117 // have size 4. All static data relocations have alignment of 1. 118 if (code == elfcpp::R_ARM_ABS8) 119 this->size_ = 1; 120 else if (code == elfcpp::R_ARM_ABS16) 121 this->size_ = 2; 122 else 123 this->size_ = 4; 124 this->align_ = 1; 125 break; 126 case RC_MISC: 127 // R_ARM_V4BX should be treated as an ARM relocation. For all 128 // others, just use defaults. 129 if (code != elfcpp::R_ARM_V4BX) 130 break; 131 // Fall through. 132 case RC_ARM: 133 this->size_ = 4; 134 this->align_ = 4; 135 break; 136 case RC_THM16: 137 this->size_ = 2; 138 this->align_ = 2; 139 break; 140 case RC_THM32: 141 this->size_ = 4; 142 this->align_ = 2; 143 break; 144 default: 145 gold_unreachable(); 146 } 147 } 148 else if (rtype == RT_DYNAMIC) 149 { 150 // With the exception of R_ARM_COPY, all dynamic relocations requires 151 // that the place being relocated is a word-aligned 32-bit object. 152 if (code != elfcpp::R_ARM_COPY) 153 { 154 this->size_ = 4; 155 this->align_ = 4; 156 } 157 } 158 159 // If no relocation operation is specified, we are done. 160 if (operation == "NONE") 161 return; 162 163 // Extract information from relocation operation. 164 Tree_node* root_node = Tree_node::make_tree(operation); 165 Tree_node* node = root_node; 166 167 // Check for an expression of the form XXX - YYY. 168 if (!node->is_leaf() 169 && node->child(0)->is_leaf() 170 && node->child(0)->name() == "-") 171 { 172 struct RAB_table_entry 173 { 174 Relative_address_base rab; 175 const char* name; 176 }; 177 178 static const RAB_table_entry rab_table[] = 179 { 180 { RAB_B_S, "( B S )" }, 181 { RAB_DELTA_B_S, "( DELTA_B ( S ) )" }, 182 { RAB_GOT_ORG, "GOT_ORG" }, 183 { RAB_P, "P" }, 184 { RAB_Pa, "Pa" }, 185 { RAB_TLS, "TLS" }, 186 { RAB_tp, "tp" } 187 }; 188 189 static size_t rab_table_size = sizeof(rab_table) / sizeof(rab_table[0]); 190 const std::string rhs(node->child(2)->s_expression()); 191 for (size_t i = 0; i < rab_table_size; ++i) 192 if (rhs == rab_table[i].name) 193 { 194 this->relative_address_base_ = rab_table[i].rab; 195 break; 196 } 197 198 gold_assert(this->relative_address_base_ != RAB_NONE); 199 if (this->relative_address_base_ == RAB_B_S) 200 this->uses_symbol_base_ = true; 201 node = node->child(1); 202 } 203 204 // Check for an expression of the form XXX | T. 205 if (!node->is_leaf() 206 && node->child(0)->is_leaf() 207 && node->child(0)->name() == "|") 208 { 209 gold_assert(node->number_of_children() == 3 210 && node->child(2)->is_leaf() 211 && node->child(2)->name() == "T"); 212 this->uses_thumb_bit_ = true; 213 node = node->child(1); 214 } 215 216 // Check for an expression of the form XXX + A. 217 if (!node->is_leaf() 218 && node->child(0)->is_leaf() 219 && node->child(0)->name() == "+") 220 { 221 gold_assert(node->number_of_children() == 3 222 && node->child(2)->is_leaf() 223 && node->child(2)->name() == "A"); 224 this->uses_addend_ = true; 225 node = node->child(1); 226 } 227 228 // Check for an expression of the form XXX(S). 229 if (!node->is_leaf() && node->child(0)->is_leaf()) 230 { 231 gold_assert(node->number_of_children() == 2 232 && node->child(1)->is_leaf() 233 && node->child(1)->name() == "S"); 234 const std::string func(node->child(0)->name()); 235 if (func == "B") 236 this->uses_symbol_base_ = true; 237 else if (func == "GOT") 238 this->uses_got_entry_ = true; 239 else if (func == "PLT") 240 this->uses_plt_entry_ = true; 241 else if (func == "Module" || func == "DELTA_B") 242 // These are used in dynamic relocations. 243 ; 244 else 245 gold_unreachable(); 246 node = node->child(1); 247 } 248 249 gold_assert(node->is_leaf() && node->name() == "S"); 250 this->uses_symbol_ = true; 251 252 delete root_node; 253 } 254 255 // Arm_reloc_property_table methods. 256 257 // Constructor. This processing informations in arm-reloc.def to 258 // initialize the table. 259 260 Arm_reloc_property_table::Arm_reloc_property_table() 261 { 262 // These appear in arm-reloc.def. Do not rename them. 263 Parse_expression A("A"), GOT_ORG("GOT_ORG"), NONE("NONE"), P("P"), 264 Pa("Pa"), S("S"), T("T"), TLS("TLS"), tp("tp"); 265 const bool Y(true), N(false); 266 267 for (unsigned int i = 0; i < Property_table_size; ++i) 268 this->table_[i] = NULL; 269 270 #undef RD 271 #define RD(name, type, deprecated, class, operation, is_implemented, \ 272 group_index, checks_oveflow) \ 273 do \ 274 { \ 275 unsigned int code = elfcpp::R_ARM_##name; \ 276 gold_assert(code < Property_table_size); \ 277 this->table_[code] = \ 278 new Arm_reloc_property(elfcpp::R_ARM_##name, "R_ARM_" #name, \ 279 Arm_reloc_property::RT_##type, deprecated, \ 280 Arm_reloc_property::RC_##class, \ 281 (operation).s_expression(), is_implemented, \ 282 group_index, checks_oveflow); \ 283 } \ 284 while(0); 285 286 #include "arm-reloc.def" 287 #undef RD 288 } 289 290 // Return a string describing a relocation code that fails to get a 291 // relocation property in get_implemented_static_reloc_property(). 292 293 std::string 294 Arm_reloc_property_table::reloc_name_in_error_message(unsigned int code) 295 { 296 gold_assert(code < Property_table_size); 297 298 const Arm_reloc_property* arp = this->table_[code]; 299 300 if (arp == NULL) 301 { 302 char buffer[100]; 303 sprintf(buffer, _("invalid reloc %u"), code); 304 return std::string(buffer); 305 } 306 307 // gold only implements static relocation codes. 308 Arm_reloc_property::Reloc_type reloc_type = arp->reloc_type(); 309 gold_assert(reloc_type == Arm_reloc_property::RT_STATIC 310 || !arp->is_implemented()); 311 312 const char* prefix = NULL; 313 switch (reloc_type) 314 { 315 case Arm_reloc_property::RT_STATIC: 316 prefix = arp->is_implemented() ? _("reloc ") : _("unimplemented reloc "); 317 break; 318 case Arm_reloc_property::RT_DYNAMIC: 319 prefix = _("dynamic reloc "); 320 break; 321 case Arm_reloc_property::RT_PRIVATE: 322 prefix = _("private reloc "); 323 break; 324 case Arm_reloc_property::RT_OBSOLETE: 325 prefix = _("obsolete reloc "); 326 break; 327 default: 328 gold_unreachable(); 329 } 330 return std::string(prefix) + arp->name(); 331 } 332 333 } // End namespace gold. 334