Commit | Line | Data |
---|---|---|
0d31c79d DK |
1 | // arm-reloc-property.cc -- ARM relocation property. |
2 | ||
b90efa5b | 3 | // Copyright (C) 2010-2015 Free Software Foundation, Inc. |
0d31c79d DK |
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 | #include "gold.h" | |
24 | ||
6cfaf60b | 25 | #include <cstdio> |
0d31c79d DK |
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), | |
b2286c10 DK |
107 | uses_thumb_bit_(false), uses_symbol_base_(false), uses_addend_(false), |
108 | uses_symbol_(false) | |
0d31c79d DK |
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"); | |
b2286c10 | 250 | this->uses_symbol_ = true; |
0d31c79d DK |
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 | { | |
9b547ce6 | 262 | // These appear in arm-reloc.def. Do not rename them. |
0d31c79d DK |
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 | ||
5c57f1be DK |
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 | ||
0d31c79d | 333 | } // End namespace gold. |