aboutsummaryrefslogtreecommitdiff
path: root/gold/arm-reloc-property.h
blob: 349d8629deb8d40f0c8dcb74bb7a5cb2db5f5f3c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
// arm-reloc-property.h -- ARM relocation properties   -*- C++ -*-

// Copyright 2010 Free Software Foundation, Inc.
// Written by Doug Kwan <dougkwan@google.com>.

// This file is part of gold.

// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
// MA 02110-1301, USA.

#ifndef GOLD_ARM_RELOC_PROPERTY_H
#define GOLD_ARM_RELOC_PROPERTY_H

namespace gold
{
// The Arm_reloc_property class is to store information about a paticular
// relocation code.

class Arm_reloc_property
{
 public:
  // Types of relocation codes.
  enum Reloc_type {
    RT_NONE,		// No relocation type.
    RT_STATIC,	// Relocations processed by static linkers.
    RT_DYNAMIC,	// Relocations processed by dynamic linkers.
    RT_PRIVATE,	// Private relocations, not supported by gold.
    RT_OBSOLETE	// Obsolete relocations that should not be used.
  };

  // Classes of relocation codes.
  enum Reloc_class {
    RC_NONE,	// No relocation class.
    RC_DATA,	// Data relocation.
    RC_ARM,	// ARM instruction relocation.
    RC_THM16,	// 16-bit THUMB instruction relocation.
    RC_THM32,	// 32-bit THUMB instruction relocation.
    RC_MISC	// Miscellaneous class.
  };

  // Types of bases of relative addressing relocation codes.
  enum Relative_address_base {
    RAB_NONE,		// Relocation is not relative addressing
    RAB_B_S,		// Address origin of output segment of defining symbol.
    RAB_DELTA_B_S,	// Change of address origin.
    RAB_GOT_ORG,	// Origin of GOT.
    RAB_P,		// Address of the place being relocated.
    RAB_Pa,		// Adjusted address (P & 0xfffffffc).
    RAB_TLS,		// Thread local storage.
    RAB_tp		// Thread pointer.
  };

  // Relocation code represented by this.
  unsigned int
  code() const
  { return this->code_; }

  // Name of the relocation code.
  const std::string&
  name() const
  { return this->name_; }
  
  // Type of relocation code.
  Reloc_type
  reloc_type() const
  { return this->reloc_type_; }

  // Whether this code is deprecated.
  bool
  is_deprecated() const
  { return this->is_deprecated_; }

  // Class of relocation code.
  Reloc_class
  reloc_class() const
  { return this->reloc_class_; }

  // Whether this code is implemented in gold.
  bool
  is_implemented() const
  { return this->is_implemented_; }

  // If code is a group relocation code, return the group number, otherwise -1.
  int
  group_index() const
  { return this->group_index_; }

  // Whether relocation checks for overflow.
  bool
  checks_overflow() const
  { return this->checks_overflow_; }

  // Return size of relocation.
  size_t
  size() const
  { return this->size_; }

  // Return alignment of relocation.
  size_t
  align() const
  { return this->align_; }

  // Whether relocation use a GOT entry.
  bool
  uses_got_entry() const
  { return this->uses_got_entry_; }

  // Whether relocation use a GOT origin.
  bool
  uses_got_origin() const
  { return this->uses_got_origin_; }
  
  // Whether relocation uses the Thumb-bit in a symbol address.
  bool
  uses_thumb_bit() const
  { return this->uses_thumb_bit_; }

  // Whether relocation uses the symbol base.
  bool
  uses_symbol_base() const
  { return this->uses_symbol_base_; }

  // Return the type of relative address base or RAB_NONE if this
  // is not a relative addressing relocation.
  Relative_address_base
  relative_address_base() const
  { return this->relative_address_base_; } 

 protected:
  // These are protected.  We only allow Arm_reloc_property_table to
  // manage Arm_reloc_property. 
  Arm_reloc_property(unsigned int code, const char* name, Reloc_type rtype,
		     bool is_deprecated, Reloc_class rclass,
		     const std::string& operation, bool is_implemented,
		     int group_index, bool checks_overflow);

  friend class Arm_reloc_property_table;
  
 private:
  // Copying is not allowed.
  Arm_reloc_property(const Arm_reloc_property&);
  Arm_reloc_property& operator=(const Arm_reloc_property&);

  // The Tree_node class is used to represent parsed relocation operations. 
  // We look at Trees to extract information about relocation operations.
  class Tree_node
  {
   public:
    typedef std::vector<Tree_node*> Tree_node_vector;

    // Construct a leaf node.
    Tree_node(const char* name)
      : is_leaf_(true), name_(name), children_()
    { }

    // Construct an internal node.  A node owns all its children and is
    // responsible for releasing them at its own destruction.
    Tree_node(Tree_node_vector::const_iterator begin,
	      Tree_node_vector::const_iterator end)
      : is_leaf_(false), name_(), children_()
    {
      for (Tree_node_vector::const_iterator p = begin; p != end; ++p)
	this->children_.push_back(*p);
    }

    ~Tree_node()
    {
      for(size_t i = 0; i <this->children_.size(); ++i)
	delete this->children_[i];
    }

    // Whether this is a leaf node.
    bool
    is_leaf() const
    { return this->is_leaf_; }

    // Return name of this.  This is only valid for a leaf node.
    const std::string&
    name() const
    {
      gold_assert(this->is_leaf_);
      return this->name_;
    }

    // Return the number of children.  This is only valid for a non-leaf node.
    size_t
    number_of_children() const
    {
      gold_assert(!this->is_leaf_);
      return this->children_.size();
    }

    // Return the i-th child of this.  This is only valid for a non-leaf node.
    Tree_node*
    child(size_t i) const
    {
      gold_assert(!this->is_leaf_ && i < this->children_.size());
      return this->children_[i];
    }

    // Parse an S-expression string and build a tree and return the root node.
    // Caller is responsible for releasing tree after use.
    static Tree_node*
    make_tree(const std::string&);

    // Convert a tree back to an S-expression string.
    std::string
    s_expression() const
    {
      if (this->is_leaf_)
	return this->name_;

      // Concatenate S-expressions of children. Enclose them with
      // a pair of parentheses and use space as token delimiters.
      std::string s("(");
      for(size_t i = 0; i <this->children_.size(); ++i)
	s = s + " " + this->children_[i]->s_expression();
      return s + " )";
    }

   private:
    // Whether this is a leaf node.
    bool is_leaf_;
    // Name of this if this is a leaf node.
    std::string name_;
    // Children of this if this a non-leaf node.
    Tree_node_vector children_;
  };

  // Relocation code.
  unsigned int code_;
  // Relocation name.
  std::string name_;
  // Type of relocation.
  Reloc_type reloc_type_;
  // Class of relocation.
  Reloc_class reloc_class_;
  // Group index (0, 1, or 2) if this is a group relocation or -1 otherwise.
  int group_index_; 
  // Size of relocation.
  size_t size_;
  // Alignment of relocation.
  size_t align_;
  // Relative address base.
  Relative_address_base relative_address_base_;
  // Whether this is deprecated.
  bool is_deprecated_ : 1;
  // Whether this is implemented in gold.
  bool is_implemented_ : 1;
  // Whether this checks overflow.
  bool checks_overflow_ : 1;
  // Whether this uses a GOT entry.
  bool uses_got_entry_ : 1;
  // Whether this uses a GOT origin.
  bool uses_got_origin_ : 1;
  // Whether this uses a PLT entry.
  bool uses_plt_entry_ : 1;
  // Whether this uses the THUMB bit in symbol address.
  bool uses_thumb_bit_ : 1;
  // Whether this uses the symbol base.
  bool uses_symbol_base_ : 1;
  // Whether this uses an addend.
  bool uses_addend_ : 1;
};

// Arm_reloc_property_table.  This table is used for looking up propeties
// of relocationt types.  The table entries are initialized using information
// from arm-reloc.def.

class Arm_reloc_property_table
{
 public:
  Arm_reloc_property_table();

  // Return an Arm_reloc_property object for CODE if it is a valid relocation
  // code or NULL otherwise.
  const Arm_reloc_property*
  get_reloc_property(unsigned int code) const
  {
    gold_assert(code < Property_table_size);
    return this->table_[code];
  }

  // Like get_reloc_property but only return non-NULL if relocation code is
  // static and implemented.
  const Arm_reloc_property*
  get_implemented_static_reloc_property(unsigned int code) const
  {
    gold_assert(code < Property_table_size);
    const Arm_reloc_property* arp = this->table_[code];
    return ((arp != NULL
	     && (arp->reloc_type() == Arm_reloc_property::RT_STATIC)
	     && arp->is_implemented())
	    ? arp
	    : NULL);
  }
  
  // Return a string describing the a relocation code that is not
  // an implemented static reloc code.
  std::string
  reloc_name_in_error_message(unsigned int code);

 private:
  // Copying is not allowed.
  Arm_reloc_property_table(const Arm_reloc_property_table&);
  Arm_reloc_property_table& operator=(const Arm_reloc_property_table&);

  // The Parse_expression class is used to convert relocation operations in
  // arm-reloc.def into S-expression strings, which are parsed again to
  // build actual expression trees.  We do not build the expression trees
  // directly because the parser for operations in arm-reloc.def is simpler
  // this way.  Coversion from S-expressions to trees is simple.
  class Parse_expression
  {
   public:
    // Construction a Parse_expression with an S-expression string.
    Parse_expression(const std::string& s_expression)
      : s_expression_(s_expression)
    { }

    // Value of this expression as an S-expression string.
    const std::string&
    s_expression() const
    { return this->s_expression_; }

    // We want to overload operators used in relocation operations so
    // that we can execute operations in arm-reloc.def to generate
    // S-expressions directly.
#define DEF_OPERATOR_OVERLOAD(op) \
    Parse_expression \
    operator op (const Parse_expression& e) \
    { \
      return Parse_expression("( " #op " " + this->s_expression_ + " " + \
			      e.s_expression_ + " )"); \
    }

    // Operator appearing in relocation operations in arm-reloc.def.
    DEF_OPERATOR_OVERLOAD(+)
    DEF_OPERATOR_OVERLOAD(-)
    DEF_OPERATOR_OVERLOAD(|)
    
   private:
    // This represented as an S-expression string.
    std::string s_expression_;
  };

#define DEF_RELOC_FUNC(name) \
  static Parse_expression \
  (name)(const Parse_expression& arg) \
  { return Parse_expression("( " #name " " + arg.s_expression() + " )"); }

  // Functions appearing in relocation operations in arm-reloc.def.
  DEF_RELOC_FUNC(B)
  DEF_RELOC_FUNC(DELTA_B)
  DEF_RELOC_FUNC(GOT)
  DEF_RELOC_FUNC(Module)
  DEF_RELOC_FUNC(PLT)

  static const unsigned int Property_table_size = 256;

  // The property table.
  Arm_reloc_property* table_[Property_table_size];
};

} // End namespace gold.

#endif // !defined(GOLD_ARM_RELOC_PROPERTY_H)