1 // arm-reloc-property.cc -- ARM relocation property.
3 // Copyright 2010 Free Software Foundation, Inc.
4 // Written by Doug Kwan <dougkwan@google.com>.
6 // This file is part of gold.
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.
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.
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.
33 #include "arm-reloc-property.h"
38 // Arm_reloc_property::Tree_node methods.
40 // Parse an S-expression S and build a tree and return the root node.
41 // Caller is responsible for releasing tree after use.
43 Arm_reloc_property::Tree_node
*
44 Arm_reloc_property::Tree_node::make_tree(const std::string
& s
)
46 std::stack
<size_t> size_stack
;
47 Tree_node_vector node_stack
;
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
, " ");
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)
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();
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
);
74 // Just push a leaf node to node_stack.
75 node_stack
.push_back(new Tree_node(token
));
77 token
= strtok(NULL
, " ");
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);
88 // Arm_reloc_property methods.
92 Arm_reloc_property::Arm_reloc_property(
98 const std::string
& operation
,
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)
109 // Set size and alignment of static and dynamic relocations.
110 if (rtype
== RT_STATIC
)
115 // Except for R_ARM_ABS16 and R_ARM_ABS8, all static data relocations
116 // have size 4. All static data relocations have alignment of 1.
117 if (code
== elfcpp::R_ARM_ABS8
)
119 else if (code
== elfcpp::R_ARM_ABS16
)
126 // R_ARM_V4BX should be treated as an ARM relocation. For all
127 // others, just use defaults.
128 if (code
!= elfcpp::R_ARM_V4BX
)
147 else if (rtype
== RT_DYNAMIC
)
149 // With the exception of R_ARM_COPY, all dynamic relocations requires
150 // that the place being relocated is a word-aligned 32-bit object.
151 if (code
!= elfcpp::R_ARM_COPY
)
158 // If no relocation operation is specified, we are done.
159 if (operation
== "NONE")
162 // Extract information from relocation operation.
163 Tree_node
* root_node
= Tree_node::make_tree(operation
);
164 Tree_node
* node
= root_node
;
166 // Check for an expression of the form XXX - YYY.
168 && node
->child(0)->is_leaf()
169 && node
->child(0)->name() == "-")
171 struct RAB_table_entry
173 Relative_address_base rab
;
177 static const RAB_table_entry rab_table
[] =
179 { RAB_B_S
, "( B S )" },
180 { RAB_DELTA_B_S
, "( DELTA_B ( S ) )" },
181 { RAB_GOT_ORG
, "GOT_ORG" },
188 static size_t rab_table_size
= sizeof(rab_table
) / sizeof(rab_table
[0]);
189 const std::string
rhs(node
->child(2)->s_expression());
190 for (size_t i
= 0; i
< rab_table_size
; ++i
)
191 if (rhs
== rab_table
[i
].name
)
193 this->relative_address_base_
= rab_table
[i
].rab
;
197 gold_assert(this->relative_address_base_
!= RAB_NONE
);
198 if (this->relative_address_base_
== RAB_B_S
)
199 this->uses_symbol_base_
= true;
200 node
= node
->child(1);
203 // Check for an expression of the form XXX | T.
205 && node
->child(0)->is_leaf()
206 && node
->child(0)->name() == "|")
208 gold_assert(node
->number_of_children() == 3
209 && node
->child(2)->is_leaf()
210 && node
->child(2)->name() == "T");
211 this->uses_thumb_bit_
= true;
212 node
= node
->child(1);
215 // Check for an expression of the form XXX + A.
217 && node
->child(0)->is_leaf()
218 && node
->child(0)->name() == "+")
220 gold_assert(node
->number_of_children() == 3
221 && node
->child(2)->is_leaf()
222 && node
->child(2)->name() == "A");
223 this->uses_addend_
= true;
224 node
= node
->child(1);
227 // Check for an expression of the form XXX(S).
228 if (!node
->is_leaf() && node
->child(0)->is_leaf())
230 gold_assert(node
->number_of_children() == 2
231 && node
->child(1)->is_leaf()
232 && node
->child(1)->name() == "S");
233 const std::string
func(node
->child(0)->name());
235 this->uses_symbol_base_
= true;
236 else if (func
== "GOT")
237 this->uses_got_entry_
= true;
238 else if (func
== "PLT")
239 this->uses_plt_entry_
= true;
240 else if (func
== "Module" || func
== "DELTA_B")
241 // These are used in dynamic relocations.
245 node
= node
->child(1);
248 gold_assert(node
->is_leaf() && node
->name() == "S");
253 // Arm_reloc_property_table methods.
255 // Constructor. This processing informations in arm-reloc.def to
256 // initialize the table.
258 Arm_reloc_property_table::Arm_reloc_property_table()
260 // These appers in arm-reloc.def. Do not rename them.
261 Parse_expression
A("A"), GOT_ORG("GOT_ORG"), NONE("NONE"), P("P"),
262 Pa("Pa"), S("S"), T("T"), TLS("TLS"), tp("tp");
263 const bool Y(true), N(false);
265 for (unsigned int i
= 0; i
< Property_table_size
; ++i
)
266 this->table_
[i
] = NULL
;
269 #define RD(name, type, deprecated, class, operation, is_implemented, \
270 group_index, checks_oveflow) \
273 unsigned int code = elfcpp::R_ARM_##name; \
274 gold_assert(code < Property_table_size); \
275 this->table_[code] = \
276 new Arm_reloc_property(elfcpp::R_ARM_##name, "R_ARM_" #name, \
277 Arm_reloc_property::RT_##type, deprecated, \
278 Arm_reloc_property::RC_##class, \
279 (operation).s_expression(), is_implemented, \
280 group_index, checks_oveflow); \
284 #include "arm-reloc.def"
288 // Return a string describing a relocation code that fails to get a
289 // relocation property in get_implemented_static_reloc_property().
292 Arm_reloc_property_table::reloc_name_in_error_message(unsigned int code
)
294 gold_assert(code
< Property_table_size
);
296 const Arm_reloc_property
* arp
= this->table_
[code
];
301 sprintf(buffer
, _("invalid reloc %u"), code
);
302 return std::string(buffer
);
305 // gold only implements static relocation codes.
306 Arm_reloc_property::Reloc_type reloc_type
= arp
->reloc_type();
307 gold_assert(reloc_type
== Arm_reloc_property::RT_STATIC
308 || !arp
->is_implemented());
310 const char* prefix
= NULL
;
313 case Arm_reloc_property::RT_STATIC
:
314 prefix
= arp
->is_implemented() ? _("reloc ") : _("unimplemented reloc ");
316 case Arm_reloc_property::RT_DYNAMIC
:
317 prefix
= _("dynamic reloc ");
319 case Arm_reloc_property::RT_PRIVATE
:
320 prefix
= _("private reloc ");
322 case Arm_reloc_property::RT_OBSOLETE
:
323 prefix
= _("obsolete reloc ");
328 return std::string(prefix
) + arp
->name();
331 } // End namespace gold.