1 // arm-reloc-property.cc -- ARM relocation property.
3 // Copyright (C) 2010-2023 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),
110 // Set size and alignment of static and dynamic relocations.
111 if (rtype
== RT_STATIC
)
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
)
120 else if (code
== elfcpp::R_ARM_ABS16
)
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
)
148 else if (rtype
== RT_DYNAMIC
)
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
)
159 // If no relocation operation is specified, we are done.
160 if (operation
== "NONE")
163 // Extract information from relocation operation.
164 Tree_node
* root_node
= Tree_node::make_tree(operation
);
165 Tree_node
* node
= root_node
;
167 // Check for an expression of the form XXX - YYY.
169 && node
->child(0)->is_leaf()
170 && node
->child(0)->name() == "-")
172 struct RAB_table_entry
174 Relative_address_base rab
;
178 static const RAB_table_entry rab_table
[] =
180 { RAB_B_S
, "( B S )" },
181 { RAB_DELTA_B_S
, "( DELTA_B ( S ) )" },
182 { RAB_GOT_ORG
, "GOT_ORG" },
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
)
194 this->relative_address_base_
= rab_table
[i
].rab
;
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);
204 // Check for an expression of the form XXX | T.
206 && node
->child(0)->is_leaf()
207 && node
->child(0)->name() == "|")
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);
216 // Check for an expression of the form XXX + A.
218 && node
->child(0)->is_leaf()
219 && node
->child(0)->name() == "+")
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);
228 // Check for an expression of the form XXX(S).
229 if (!node
->is_leaf() && node
->child(0)->is_leaf())
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());
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.
246 node
= node
->child(1);
249 gold_assert(node
->is_leaf() && node
->name() == "S");
250 this->uses_symbol_
= true;
255 // Arm_reloc_property_table methods.
257 // Constructor. This processing informations in arm-reloc.def to
258 // initialize the table.
260 Arm_reloc_property_table::Arm_reloc_property_table()
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);
267 for (unsigned int i
= 0; i
< Property_table_size
; ++i
)
268 this->table_
[i
] = NULL
;
271 #define RD(name, type, deprecated, class, operation, is_implemented, \
272 group_index, checks_oveflow) \
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); \
286 #include "arm-reloc.def"
290 // Return a string describing a relocation code that fails to get a
291 // relocation property in get_implemented_static_reloc_property().
294 Arm_reloc_property_table::reloc_name_in_error_message(unsigned int code
)
296 gold_assert(code
< Property_table_size
);
298 const Arm_reloc_property
* arp
= this->table_
[code
];
303 sprintf(buffer
, _("invalid reloc %u"), code
);
304 return std::string(buffer
);
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());
312 const char* prefix
= NULL
;
315 case Arm_reloc_property::RT_STATIC
:
316 prefix
= arp
->is_implemented() ? _("reloc ") : _("unimplemented reloc ");
318 case Arm_reloc_property::RT_DYNAMIC
:
319 prefix
= _("dynamic reloc ");
321 case Arm_reloc_property::RT_PRIVATE
:
322 prefix
= _("private reloc ");
324 case Arm_reloc_property::RT_OBSOLETE
:
325 prefix
= _("obsolete reloc ");
330 return std::string(prefix
) + arp
->name();
333 } // End namespace gold.