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