Halide  12.0.1
Halide compiler and libraries
Elf.h
Go to the documentation of this file.
1 #ifndef HALIDE_ELF_H
2 #define HALIDE_ELF_H
3 
4 #include <algorithm>
5 #include <iterator>
6 #include <list>
7 #include <memory>
8 #include <string>
9 #include <utility>
10 #include <vector>
11 
12 namespace Halide {
13 namespace Internal {
14 namespace Elf {
15 
16 // This ELF parser mostly deserializes the object into a graph
17 // structure in memory. It replaces indices into tables (sections,
18 // symbols, etc.) with a weakly referenced graph of pointers. The
19 // Object datastructure owns all of the objects. This namespace exists
20 // because it is very difficult to use LLVM's object parser to modify
21 // an object (it's fine for parsing only). This was built using
22 // http://www.skyfree.org/linux/references/ELF_Format.pdf as a reference
23 // for the ELF structs and constants.
24 
25 class Object;
26 class Symbol;
27 class Section;
28 class Relocation;
29 
30 // Helpful wrapper to allow range-based for loops.
31 template<typename T>
33  T b, e;
34 
35 public:
36  iterator_range(T b, T e)
37  : b(b), e(e) {
38  }
39 
40  T begin() const {
41  return b;
42  }
43  T end() const {
44  return e;
45  }
46 };
47 
48 /** Describes a symbol */
49 class Symbol {
50 public:
51  enum Binding : uint8_t {
52  STB_LOCAL = 0,
54  STB_WEAK = 2,
55  STB_LOPROC = 13,
56  STB_HIPROC = 15,
57  };
58 
59  enum Type : uint8_t {
62  STT_FUNC = 2,
64  STT_FILE = 4,
65  STT_LOPROC = 13,
66  STT_HIPROC = 15,
67  };
68 
74  };
75 
76 private:
77  std::string name;
78  const Section *definition = nullptr;
79  uint64_t offset = 0;
80  uint32_t size = 0;
81  Binding binding = STB_LOCAL;
82  Type type = STT_NOTYPE;
83  Visibility visibility = STV_DEFAULT;
84 
85 public:
86  Symbol() = default;
87  Symbol(const std::string &name)
88  : name(name) {
89  }
90 
91  /** Accesses the name of this symbol. */
92  ///@{
93  Symbol &set_name(const std::string &name) {
94  this->name = name;
95  return *this;
96  }
97  const std::string &get_name() const {
98  return name;
99  }
100  ///@}
101 
102  /** Accesses the type of this symbol. */
103  ///@{
105  this->type = type;
106  return *this;
107  }
108  Type get_type() const {
109  return type;
110  }
111  ///@}
112 
113  /** Accesses the properties that describe the definition of this symbol. */
114  ///@{
115  Symbol &define(const Section *section, uint64_t offset, uint32_t size) {
116  this->definition = section;
117  this->offset = offset;
118  this->size = size;
119  return *this;
120  }
121  bool is_defined() const {
122  return definition != nullptr;
123  }
124  const Section *get_section() const {
125  return definition;
126  }
128  return offset;
129  }
130  uint32_t get_size() const {
131  return size;
132  }
133  ///@}
134 
135  /** Access the binding and visibility of this symbol. See the ELF
136  * spec for more information about these properties. */
137  ///@{
139  this->binding = binding;
140  return *this;
141  }
143  this->visibility = visibility;
144  return *this;
145  }
147  return binding;
148  }
150  return visibility;
151  }
152  ///@}
153 };
154 
155 /** Describes a relocation to be applied to an offset of a section in
156  * an Object. */
157 class Relocation {
158  uint32_t type = 0;
159  uint64_t offset = 0;
160  int64_t addend = 0;
161  const Symbol *symbol = nullptr;
162 
163 public:
164  Relocation() = default;
165  Relocation(uint32_t type, uint64_t offset, int64_t addend, const Symbol *symbol)
166  : type(type), offset(offset), addend(addend), symbol(symbol) {
167  }
168 
169  /** The type of relocation to be applied. The meaning of this
170  * value depends on the machine of the object. */
171  ///@{
173  this->type = type;
174  return *this;
175  }
176  uint32_t get_type() const {
177  return type;
178  }
179  ///@}
180 
181  /** Where to apply the relocation. This is relative to the section
182  * the relocation belongs to. */
183  ///@{
185  this->offset = offset;
186  return *this;
187  }
189  return offset;
190  }
191  ///@}
192 
193  /** The value to replace with the relocation is the address of the symbol plus the addend. */
194  ///@{
195  Relocation &set_symbol(const Symbol *symbol) {
196  this->symbol = symbol;
197  return *this;
198  }
200  this->addend = addend;
201  return *this;
202  }
203  const Symbol *get_symbol() const {
204  return symbol;
205  }
206  int64_t get_addend() const {
207  return addend;
208  }
209  ///@}
210 };
211 
212 /** Describes a section of an object file. */
213 class Section {
214 public:
215  enum Type : uint32_t {
216  SHT_NULL = 0,
220  SHT_RELA = 4,
221  SHT_HASH = 5,
223  SHT_NOTE = 7,
225  SHT_REL = 9,
226  SHT_SHLIB = 10,
228  SHT_LOPROC = 0x70000000,
229  SHT_HIPROC = 0x7fffffff,
230  SHT_LOUSER = 0x80000000,
231  SHT_HIUSER = 0xffffffff,
232  };
233 
234  enum Flag : uint32_t {
235  SHF_WRITE = 0x1,
236  SHF_ALLOC = 0x2,
238  SHF_MASKPROC = 0xf0000000,
239  };
240 
241  typedef std::vector<Relocation> RelocationList;
242  typedef RelocationList::iterator relocation_iterator;
243  typedef RelocationList::const_iterator const_relocation_iterator;
244 
245  typedef std::vector<char>::iterator contents_iterator;
246  typedef std::vector<char>::const_iterator const_contents_iterator;
247 
248 private:
249  std::string name;
250  Type type = SHT_NULL;
251  uint32_t flags = 0;
252  std::vector<char> contents;
253  // Sections may have a size larger than the contents.
254  uint64_t size = 0;
255  uint64_t alignment = 1;
256  RelocationList relocs;
257 
258 public:
259  Section() = default;
260  Section(const std::string &name, Type type)
261  : name(name), type(type) {
262  }
263 
264  Section &set_name(const std::string &name) {
265  this->name = name;
266  return *this;
267  }
268  const std::string &get_name() const {
269  return name;
270  }
271 
273  this->type = type;
274  return *this;
275  }
276  Type get_type() const {
277  return type;
278  }
279 
281  this->flags |= flag;
282  return *this;
283  }
285  this->flags &= ~flag;
286  return *this;
287  }
289  this->flags = flags;
290  return *this;
291  }
292  uint32_t get_flags() const {
293  return flags;
294  }
295  bool is_alloc() const {
296  return (flags & SHF_ALLOC) != 0;
297  }
298  bool is_writable() const {
299  return (flags & SHF_WRITE) != 0;
300  }
301 
302  /** Get or set the size of the section. The size may be larger
303  * than the content. */
304  ///@{
306  this->size = size;
307  return *this;
308  }
309  uint64_t get_size() const {
310  return std::max((uint64_t)size, (uint64_t)contents.size());
311  }
312  ///@}
313 
315  this->alignment = alignment;
316  return *this;
317  }
319  return alignment;
320  }
321 
322  Section &set_contents(std::vector<char> contents) {
323  this->contents = std::move(contents);
324  return *this;
325  }
326  template<typename It>
327  Section &set_contents(It begin, It end) {
328  this->contents.assign(begin, end);
329  return *this;
330  }
331  template<typename It>
332  Section &append_contents(It begin, It end) {
333  this->contents.insert(this->contents.end(), begin, end);
334  return *this;
335  }
336  template<typename It>
337  Section &prepend_contents(It begin, It end) {
338  typedef typename std::iterator_traits<It>::value_type T;
339  uint64_t size_bytes = std::distance(begin, end) * sizeof(T);
340  this->contents.insert(this->contents.begin(), begin, end);
341 
342  // When we add data to the start of the section, we need to fix up
343  // the offsets of the relocations linked to this section.
344  for (Relocation &r : relocations()) {
345  r.set_offset(r.get_offset() + size_bytes);
346  }
347 
348  return *this;
349  }
350  /** Set, append or prepend an object to the contents, assuming T is a
351  * trivially copyable datatype. */
352  template<typename T>
353  Section &set_contents(const std::vector<T> &contents) {
354  this->contents.assign((const char *)contents.data(), (const char *)(contents.data() + contents.size()));
355  return *this;
356  }
357  template<typename T>
358  Section &append_contents(const T &x) {
359  return append_contents((const char *)&x, (const char *)(&x + 1));
360  }
361  template<typename T>
362  Section &prepend_contents(const T &x) {
363  return prepend_contents((const char *)&x, (const char *)(&x + 1));
364  }
365  const std::vector<char> &get_contents() const {
366  return contents;
367  }
369  return contents.begin();
370  }
372  return contents.end();
373  }
375  return contents.begin();
376  }
378  return contents.end();
379  }
380  const char *contents_data() const {
381  return contents.data();
382  }
383  size_t contents_size() const {
384  return contents.size();
385  }
386  bool contents_empty() const {
387  return contents.empty();
388  }
389 
390  Section &set_relocations(std::vector<Relocation> relocs) {
391  this->relocs = std::move(relocs);
392  return *this;
393  }
394  template<typename It>
395  Section &set_relocations(It begin, It end) {
396  this->relocs.assign(begin, end);
397  return *this;
398  }
399  void add_relocation(const Relocation &reloc) {
400  relocs.push_back(reloc);
401  }
403  return relocs.begin();
404  }
406  return relocs.end();
407  }
409  return {relocs.begin(), relocs.end()};
410  }
412  return relocs.begin();
413  }
415  return relocs.end();
416  }
418  return {relocs.begin(), relocs.end()};
419  }
420  size_t relocations_size() const {
421  return relocs.size();
422  }
423 };
424 
425 /** Base class for a target architecture to implement the target
426  * specific aspects of linking. */
427 class Linker {
428 public:
429  virtual ~Linker() = default;
430 
431  virtual uint16_t get_machine() = 0;
432  virtual uint32_t get_flags() = 0;
433  virtual uint32_t get_version() = 0;
434  virtual void append_dynamic(Section &dynamic) = 0;
435 
436  /** Add or get an entry to the global offset table (GOT) with a
437  * relocation pointing to sym. */
438  virtual uint64_t get_got_entry(Section &got, const Symbol &sym) = 0;
439 
440  /** Check to see if this relocation should go through the PLT. */
441  virtual bool needs_plt_entry(const Relocation &reloc) = 0;
442 
443  /** Add a PLT entry for a symbol sym defined externally. Returns a
444  * symbol representing the PLT entry. */
445  virtual Symbol add_plt_entry(const Symbol &sym, Section &plt, Section &got,
446  const Symbol &got_sym) = 0;
447 
448  /** Perform a relocation. This function may opt to not apply the
449  * relocation, and return a new relocation to be performed at
450  * runtime. This requires that the section to apply the relocation
451  * to is writable at runtime. */
452  virtual Relocation relocate(uint64_t fixup_offset, char *fixup_addr, uint64_t type,
453  const Symbol *sym, uint64_t sym_offset, int64_t addend,
454  Section &got) = 0;
455 };
456 
457 /** Holds all of the relevant sections and symbols for an object. */
458 class Object {
459 public:
460  enum Type : uint16_t {
461  ET_NONE = 0,
462  ET_REL = 1,
463  ET_EXEC = 2,
464  ET_DYN = 3,
465  ET_CORE = 4,
466  ET_LOPROC = 0xff00,
467  ET_HIPROC = 0xffff,
468  };
469 
470  // We use lists for sections and symbols to avoid iterator
471  // invalidation when we modify the containers.
472  typedef std::list<Section> SectionList;
473  typedef typename SectionList::iterator section_iterator;
474  typedef typename SectionList::const_iterator const_section_iterator;
475 
476  typedef std::list<Symbol> SymbolList;
477  typedef typename SymbolList::iterator symbol_iterator;
478  typedef typename SymbolList::const_iterator const_symbol_iterator;
479 
480 private:
481  SectionList secs;
482  SymbolList syms;
483 
484  Type type = ET_NONE;
485  uint16_t machine = 0;
486  uint32_t version = 0;
487  uint64_t entry = 0;
488  uint32_t flags = 0;
489 
490  Object(const Object &);
491  void operator=(const Object &);
492 
493 public:
494  Object() = default;
495 
496  Type get_type() const {
497  return type;
498  }
500  return machine;
501  }
503  return version;
504  }
505  uint64_t get_entry() const {
506  return entry;
507  }
508  uint32_t get_flags() const {
509  return flags;
510  }
511 
513  this->type = type;
514  return *this;
515  }
517  this->machine = machine;
518  return *this;
519  }
521  this->version = version;
522  return *this;
523  }
525  this->entry = entry;
526  return *this;
527  }
529  this->flags = flags;
530  return *this;
531  }
532 
533  /** Parse an object in memory to an Object. */
534  static std::unique_ptr<Object> parse_object(const char *data, size_t size);
535 
536  /** Write a shared object in memory. */
537  std::vector<char> write_shared_object(Linker *linker, const std::vector<std::string> &depedencies = {},
538  const std::string &soname = "");
539 
541  return secs.begin();
542  }
544  return secs.end();
545  }
547  return {secs.begin(), secs.end()};
548  }
550  return secs.begin();
551  }
553  return secs.end();
554  }
556  return {secs.begin(), secs.end()};
557  }
558  size_t sections_size() const {
559  return secs.size();
560  }
561  section_iterator find_section(const std::string &name);
562 
563  section_iterator add_section(const std::string &name, Section::Type type);
566  return secs.erase(i);
567  }
568 
569  section_iterator merge_sections(const std::vector<section_iterator> &sections);
571 
573  return syms.begin();
574  }
576  return syms.end();
577  }
579  return {syms.begin(), syms.end()};
580  }
582  return syms.begin();
583  }
585  return syms.end();
586  }
588  return {syms.begin(), syms.end()};
589  }
590  size_t symbols_size() const {
591  return syms.size();
592  }
593  symbol_iterator find_symbol(const std::string &name);
594  const_symbol_iterator find_symbol(const std::string &name) const;
595 
596  symbol_iterator add_symbol(const std::string &name);
597 };
598 
599 } // namespace Elf
600 } // namespace Internal
601 } // namespace Halide
602 
603 #endif
Base class for a target architecture to implement the target specific aspects of linking.
Definition: Elf.h:427
virtual Symbol add_plt_entry(const Symbol &sym, Section &plt, Section &got, const Symbol &got_sym)=0
Add a PLT entry for a symbol sym defined externally.
virtual void append_dynamic(Section &dynamic)=0
virtual bool needs_plt_entry(const Relocation &reloc)=0
Check to see if this relocation should go through the PLT.
virtual uint32_t get_flags()=0
virtual uint32_t get_version()=0
virtual uint64_t get_got_entry(Section &got, const Symbol &sym)=0
Add or get an entry to the global offset table (GOT) with a relocation pointing to sym.
virtual uint16_t get_machine()=0
virtual Relocation relocate(uint64_t fixup_offset, char *fixup_addr, uint64_t type, const Symbol *sym, uint64_t sym_offset, int64_t addend, Section &got)=0
Perform a relocation.
Holds all of the relevant sections and symbols for an object.
Definition: Elf.h:458
uint16_t get_machine() const
Definition: Elf.h:499
symbol_iterator symbols_end()
Definition: Elf.h:575
section_iterator erase_section(section_iterator i)
Definition: Elf.h:565
symbol_iterator find_symbol(const std::string &name)
std::vector< char > write_shared_object(Linker *linker, const std::vector< std::string > &depedencies={}, const std::string &soname="")
Write a shared object in memory.
const_section_iterator sections_begin() const
Definition: Elf.h:549
section_iterator sections_end()
Definition: Elf.h:543
SymbolList::const_iterator const_symbol_iterator
Definition: Elf.h:478
section_iterator find_section(const std::string &name)
static std::unique_ptr< Object > parse_object(const char *data, size_t size)
Parse an object in memory to an Object.
iterator_range< const_section_iterator > sections() const
Definition: Elf.h:555
Object & set_machine(uint16_t machine)
Definition: Elf.h:516
section_iterator add_section(const std::string &name, Section::Type type)
uint32_t get_flags() const
Definition: Elf.h:508
Object & set_type(Type type)
Definition: Elf.h:512
iterator_range< const_symbol_iterator > symbols() const
Definition: Elf.h:587
SymbolList::iterator symbol_iterator
Definition: Elf.h:477
Type get_type() const
Definition: Elf.h:496
const_symbol_iterator find_symbol(const std::string &name) const
const_section_iterator sections_end() const
Definition: Elf.h:552
SectionList::const_iterator const_section_iterator
Definition: Elf.h:474
const_symbol_iterator symbols_begin() const
Definition: Elf.h:581
section_iterator add_relocation_section(const Section &for_section)
size_t symbols_size() const
Definition: Elf.h:590
section_iterator merge_text_sections()
Object & set_entry(uint64_t entry)
Definition: Elf.h:524
uint64_t get_entry() const
Definition: Elf.h:505
section_iterator merge_sections(const std::vector< section_iterator > &sections)
Object & set_flags(uint32_t flags)
Definition: Elf.h:528
const_symbol_iterator symbols_end() const
Definition: Elf.h:584
std::list< Symbol > SymbolList
Definition: Elf.h:476
symbol_iterator add_symbol(const std::string &name)
symbol_iterator symbols_begin()
Definition: Elf.h:572
size_t sections_size() const
Definition: Elf.h:558
uint32_t get_version() const
Definition: Elf.h:502
section_iterator sections_begin()
Definition: Elf.h:540
iterator_range< section_iterator > sections()
Definition: Elf.h:546
iterator_range< symbol_iterator > symbols()
Definition: Elf.h:578
SectionList::iterator section_iterator
Definition: Elf.h:473
Object & set_version(uint32_t version)
Definition: Elf.h:520
std::list< Section > SectionList
Definition: Elf.h:472
Describes a relocation to be applied to an offset of a section in an Object.
Definition: Elf.h:157
int64_t get_addend() const
The value to replace with the relocation is the address of the symbol plus the addend.
Definition: Elf.h:206
const Symbol * get_symbol() const
The value to replace with the relocation is the address of the symbol plus the addend.
Definition: Elf.h:203
Relocation & set_type(uint32_t type)
The type of relocation to be applied.
Definition: Elf.h:172
Relocation & set_symbol(const Symbol *symbol)
The value to replace with the relocation is the address of the symbol plus the addend.
Definition: Elf.h:195
Relocation(uint32_t type, uint64_t offset, int64_t addend, const Symbol *symbol)
Definition: Elf.h:165
Relocation & set_offset(uint64_t offset)
Where to apply the relocation.
Definition: Elf.h:184
uint64_t get_offset() const
Where to apply the relocation.
Definition: Elf.h:188
Relocation & set_addend(int64_t addend)
The value to replace with the relocation is the address of the symbol plus the addend.
Definition: Elf.h:199
uint32_t get_type() const
The type of relocation to be applied.
Definition: Elf.h:176
Describes a section of an object file.
Definition: Elf.h:213
Section & remove_flag(Flag flag)
Definition: Elf.h:284
Section & prepend_contents(It begin, It end)
Definition: Elf.h:337
Section & set_name(const std::string &name)
Definition: Elf.h:264
Section & append_contents(It begin, It end)
Definition: Elf.h:332
bool contents_empty() const
Definition: Elf.h:386
Section & set_flag(Flag flag)
Definition: Elf.h:280
size_t relocations_size() const
Definition: Elf.h:420
Section & set_relocations(It begin, It end)
Definition: Elf.h:395
const std::string & get_name() const
Definition: Elf.h:268
uint64_t get_alignment() const
Definition: Elf.h:318
Section & prepend_contents(const T &x)
Definition: Elf.h:362
size_t contents_size() const
Definition: Elf.h:383
Section & set_contents(const std::vector< T > &contents)
Set, append or prepend an object to the contents, assuming T is a trivially copyable datatype.
Definition: Elf.h:353
Section & set_alignment(uint64_t alignment)
Definition: Elf.h:314
Section & append_contents(const T &x)
Definition: Elf.h:358
relocation_iterator relocations_end()
Definition: Elf.h:405
uint32_t get_flags() const
Definition: Elf.h:292
uint64_t get_size() const
Get or set the size of the section.
Definition: Elf.h:309
std::vector< char >::iterator contents_iterator
Definition: Elf.h:245
relocation_iterator relocations_begin()
Definition: Elf.h:402
void add_relocation(const Relocation &reloc)
Definition: Elf.h:399
const char * contents_data() const
Definition: Elf.h:380
RelocationList::iterator relocation_iterator
Definition: Elf.h:242
Section & set_flags(uint32_t flags)
Definition: Elf.h:288
Section & set_contents(std::vector< char > contents)
Definition: Elf.h:322
RelocationList::const_iterator const_relocation_iterator
Definition: Elf.h:243
const_contents_iterator contents_begin() const
Definition: Elf.h:374
contents_iterator contents_begin()
Definition: Elf.h:368
iterator_range< const_relocation_iterator > relocations() const
Definition: Elf.h:417
iterator_range< relocation_iterator > relocations()
Definition: Elf.h:408
contents_iterator contents_end()
Definition: Elf.h:371
const_relocation_iterator relocations_begin() const
Definition: Elf.h:411
const std::vector< char > & get_contents() const
Definition: Elf.h:365
std::vector< char >::const_iterator const_contents_iterator
Definition: Elf.h:246
Section(const std::string &name, Type type)
Definition: Elf.h:260
Type get_type() const
Definition: Elf.h:276
std::vector< Relocation > RelocationList
Definition: Elf.h:241
bool is_writable() const
Definition: Elf.h:298
bool is_alloc() const
Definition: Elf.h:295
Section & set_size(uint64_t size)
Get or set the size of the section.
Definition: Elf.h:305
const_contents_iterator contents_end() const
Definition: Elf.h:377
const_relocation_iterator relocations_end() const
Definition: Elf.h:414
Section & set_contents(It begin, It end)
Definition: Elf.h:327
Section & set_type(Type type)
Definition: Elf.h:272
Section & set_relocations(std::vector< Relocation > relocs)
Definition: Elf.h:390
Describes a symbol.
Definition: Elf.h:49
Symbol & set_name(const std::string &name)
Accesses the name of this symbol.
Definition: Elf.h:93
Symbol(const std::string &name)
Definition: Elf.h:87
uint64_t get_offset() const
Accesses the properties that describe the definition of this symbol.
Definition: Elf.h:127
Visibility get_visibility() const
Access the binding and visibility of this symbol.
Definition: Elf.h:149
Symbol & define(const Section *section, uint64_t offset, uint32_t size)
Accesses the properties that describe the definition of this symbol.
Definition: Elf.h:115
Type get_type() const
Accesses the type of this symbol.
Definition: Elf.h:108
Symbol & set_type(Type type)
Accesses the type of this symbol.
Definition: Elf.h:104
const std::string & get_name() const
Accesses the name of this symbol.
Definition: Elf.h:97
bool is_defined() const
Accesses the properties that describe the definition of this symbol.
Definition: Elf.h:121
const Section * get_section() const
Accesses the properties that describe the definition of this symbol.
Definition: Elf.h:124
uint32_t get_size() const
Accesses the properties that describe the definition of this symbol.
Definition: Elf.h:130
Symbol & set_visibility(Visibility visibility)
Access the binding and visibility of this symbol.
Definition: Elf.h:142
Symbol & set_binding(Binding binding)
Access the binding and visibility of this symbol.
Definition: Elf.h:138
Binding get_binding() const
Access the binding and visibility of this symbol.
Definition: Elf.h:146
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
@ Internal
Not visible externally, similar to 'static' linkage in C.
Expr max(const FuncRef &a, const FuncRef &b)
Definition: Func.h:581
char * end
Definition: printer.h:32
unsigned __INT64_TYPE__ uint64_t
signed __INT64_TYPE__ int64_t
unsigned __INT8_TYPE__ uint8_t
unsigned __INT16_TYPE__ uint16_t
unsigned __INT32_TYPE__ uint32_t
Types in the halide type system.
Definition: Type.h:269