1// Copyright (c) 2013 Austin T. Clements. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4
5#ifndef _ELFPP_DATA_HH_
6#define _ELFPP_DATA_HH_
7
8#include "common.hh"
9
10#include <cstdint>
11#include <cstring>
12#include <string>
13
14ELFPP_BEGIN_NAMESPACE
15
16// Object file classes (ELF64 table 3)
17enum class elfclass : unsigned char
18{
19 _32 = 1, // 32-bit objects
20 _64 = 2, // 64-bit objects
21};
22
23std::string
24to_string(elfclass v);
25
26// Common basic data types
27struct ElfTypes
28{
29 typedef std::uint16_t Half;
30 typedef std::uint32_t Word;
31 typedef std::int32_t Sword;
32};
33
34struct Elf32 : public ElfTypes
35{
36 // ELF class
37 static const elfclass cls = elfclass::_32;
38
39 // Basic data types (ELF32 figure 1-2)
40 typedef std::uint32_t Addr;
41 typedef std::uint32_t Off;
42
43 // Predicated types
44 typedef Word Word32_Xword64;
45
46 template<typename t32, typename t64>
47 struct pick
48 {
49 typedef t32 t;
50 };
51};
52
53struct Elf64 : ElfTypes
54{
55 // ELF class
56 static const elfclass cls = elfclass::_64;
57
58 // Basic data types (ELF64 table 1)
59 typedef std::uint64_t Addr;
60 typedef std::uint64_t Off;
61 typedef std::uint64_t Xword;
62 typedef std::int64_t Sxword;
63
64 // Predicated types
65 typedef Xword Word32_Xword64;
66
67 template<typename t32, typename t64>
68 struct pick
69 {
70 typedef t64 t;
71 };
72};
73
74// Data encodings (ELF64 table 4)
75enum class elfdata : unsigned char
76{
77 lsb = 1,
78 msb = 2,
79};
80
81std::string
82to_string(elfdata v);
83
84// Operating system and ABI identifiers (ELF64 table 5)
85enum class elfosabi : unsigned char
86{
87 sysv = 0,
88 hpux = 1,
89 standalone = 255,
90};
91
92std::string
93to_string(elfosabi v);
94
95// Object file types (ELF64 table 6)
96enum class et : ElfTypes::Half
97{
98 none = 0, // No file type
99 rel = 1, // Relocatable object file
100 exec = 2, // Executable file
101 dyn = 3, // Shared object file
102 core = 4, // Core file
103 loos = 0xfe00, // Environment-specific use
104 hios = 0xfeff,
105 loproc = 0xff00, // Processor-specific use
106 hiproc = 0xffff,
107};
108
109std::string
110to_string(et v);
111
112// ELF header (ELF32 figure 1-3, ELF64 figure 2)
113template<typename E = Elf64, byte_order Order = byte_order::native>
114struct Ehdr
115{
116 typedef E types;
117 static const byte_order order = Order;
118
119 // ELF identification
120 unsigned char ei_magic[4];
121 elfclass ei_class;
122 elfdata ei_data;
123 unsigned char ei_version;
124 elfosabi ei_osabi;
125 unsigned char ei_abiversion;
126 unsigned char ei_pad[7];
127
128 et type; // Object file type
129 typename E::Half machine; // Machine type
130 typename E::Word version; // Object file version
131 typename E::Addr entry; // Entry point address
132 typename E::Off phoff; // Program header offset
133 typename E::Off shoff; // Section header offset
134 typename E::Word flags; // Processor-specific flags
135 typename E::Half ehsize; // ELF header size
136 typename E::Half phentsize; // Size of program header entry
137 typename E::Half phnum; // Number of program header entries
138 typename E::Half shentsize; // Size of section header entry
139 typename E::Half shnum; // Number of section header entries
140 typename E::Half shstrndx; // Section name string table index
141
142 template<typename E2>
143 void from(const E2 &o)
144 {
145 std::memcpy(ei_magic, o.ei_magic, sizeof(ei_magic));
146 ei_class = swizzle(o.ei_class, o.order, order);
147 ei_data = swizzle(o.ei_data, o.order, order);
148 ei_version = swizzle(o.ei_version, o.order, order);
149 ei_osabi = swizzle(o.ei_osabi, o.order, order);
150 ei_abiversion = swizzle(o.ei_abiversion, o.order, order);
151 std::memcpy(ei_pad, o.ei_pad, sizeof(ei_pad));
152
153 type = swizzle(o.type, o.order, order);
154 machine = swizzle(o.machine, o.order, order);
155 version = swizzle(o.version, o.order, order);
156 entry = swizzle(o.entry, o.order, order);
157 phoff = swizzle(o.phoff, o.order, order);
158 shoff = swizzle(o.shoff, o.order, order);
159 flags = swizzle(o.flags, o.order, order);
160 ehsize = swizzle(o.ehsize, o.order, order);
161 phentsize = swizzle(o.phentsize, o.order, order);
162 phnum = swizzle(o.phnum, o.order, order);
163 shentsize = swizzle(o.shentsize, o.order, order);
164 shnum = swizzle(o.shnum, o.order, order);
165 shstrndx = swizzle(o.shstrndx, o.order, order);
166 }
167};
168
169// Special section indices (ELF32 figure 1-7, ELF64 table 7)
170//
171// This is an integer with a few special values, so this is a regular
172// enum, rather than a type-safe enum. However, this is declared in a
173// namespace and then used to avoid polluting the elf:: namespace.
174namespace enums {
175enum shn : ElfTypes::Half // This is a Word in Shdr and Half in Sym.
176{
177 undef = 0, // Undefined or meaningless
178
179 loproc = 0xff00, // Processor-specific use
180 hiproc = 0xff1f,
181 loos = 0xff20, // Environment-specific use
182 hios = 0xff3f,
183
184 abs = 0xfff1, // Reference is an absolute value
185 common = 0xfff2, // Symbol declared as a common block
186};
187
188std::string
189to_string(shn v);
190}
191
192using enums::shn;
193
194// Section types (ELF64 table 8)
195enum class sht : ElfTypes::Word
196{
197 null = 0, // Marks an unseen section header
198 progbits = 1, // Contains information defined by the program
199 symtab = 2, // Contains a linker symbol table
200 strtab = 3, // Contains a string table
201 rela = 4, // Contains "Rela" type relocation entries
202 hash = 5, // Contains a symbol hash table
203 dynamic = 6, // Contains dynamic linking tables
204 note = 7, // Contains note information
205 nobits = 8, // Contains uninitialized space;
206 // does not occupy any space in the file
207 rel = 9, // Contains "Rel" type relocation entries
208 shlib = 10, // Reserved
209 dynsym = 11, // Contains a dynamic loader symbol table
210 loos = 0x60000000, // Environment-specific use
211 hios = 0x6FFFFFFF,
212 loproc = 0x70000000, // Processor-specific use
213 hiproc = 0x7FFFFFFF,
214};
215
216std::string
217to_string(sht v);
218
219// Section attributes (ELF64 table 9). Note: This is an Elf32_Word in
220// ELF32. We use the larger ELF64 type for the canonical
221// representation and switch it out for a plain Elf32_Word in the
222// ELF32 format.
223enum class shf : Elf64::Xword
224{
225 write = 0x1, // Section contains writable data
226 alloc = 0x2, // Section is allocated in memory image of program
227 execinstr = 0x4, // Section contains executable instructions
228 maskos = 0x0F000000, // Environment-specific use
229 maskproc = 0xF0000000, // Processor-specific use
230};
231
232std::string
233to_string(shf v);
234
235static inline constexpr shf operator&(shf a, shf b)
236{
237 return (shf)((std::uint64_t)a & (std::uint64_t)b);
238}
239
240static inline constexpr shf operator|(shf a, shf b)
241{
242 return (shf)((std::uint64_t)a | (std::uint64_t)b);
243}
244
245static inline constexpr shf operator^(shf a, shf b)
246{
247 return (shf)((std::uint64_t)a ^ (std::uint64_t)b);
248}
249
250static inline constexpr shf operator~(shf a)
251{
252 return (shf)~((std::uint64_t)a);
253}
254
255static inline shf& operator&=(shf &a, shf b)
256{
257 a = a & b;
258 return a;
259}
260
261static inline shf& operator|=(shf &a, shf b)
262{
263 a = a | b;
264 return a;
265}
266
267static inline shf& operator^=(shf &a, shf b)
268{
269 a = a ^ b;
270 return a;
271}
272
273// Section header (ELF32 figure 1-8, ELF64 figure 3)
274template<typename E = Elf64, byte_order Order = byte_order::native>
275struct Shdr
276{
277 typedef E types;
278 static const byte_order order = Order;
279 // Section numbers are half-words in some structures and full
280 // words in others. Here we declare a local shn type that is
281 // elf::shn for the native byte order, but the full word for
282 // specific encoding byte orders.
283 typedef typename internal::OrderPick<Order, elf::shn, typename E::Word, typename E::Word>::T shn;
284
285 typename E::Word name; // Section name
286 sht type; // Section type
287 typename E::template pick<typename E::Word, shf>::t flags; // Section attributes
288 typename E::Addr addr; // Virtual address in memory
289 typename E::Off offset; // Offset in file
290 typename E::Word32_Xword64 size; // Size of section
291 shn link; // Link to other section
292 typename E::Word info; // Miscellaneous information
293 typename E::Word32_Xword64 addralign; // Address alignment boundary
294 typename E::Word32_Xword64 entsize; // Size of entries, if section has table
295
296 template<typename E2>
297 void from(const E2 &o)
298 {
299 name = swizzle(o.name, o.order, order);
300 type = swizzle(o.type, o.order, order);
301 flags = (decltype(flags))swizzle(o.flags, o.order, order);
302 addr = swizzle(o.addr, o.order, order);
303 offset = swizzle(o.offset, o.order, order);
304 size = swizzle(o.size, o.order, order);
305 link = (decltype(link))swizzle((typename E::Word)o.link, o.order, order);
306 info = swizzle(o.info, o.order, order);
307 addralign = swizzle(o.addralign, o.order, order);
308 entsize = swizzle(o.entsize, o.order, order);
309 }
310};
311
312// Segment types (ELF64 table 16)
313enum class pt : ElfTypes::Word
314{
315 null = 0, // Unused entry
316 load = 1, // Loadable segment
317 dynamic = 2, // Dynamic linking tables
318 interp = 3, // Program interpreter path name
319 note = 4, // Note sections
320 shlib = 5, // Reserved
321 phdr = 6, // Program header table
322 loos = 0x60000000, // Environment-specific use
323 hios = 0x6FFFFFFF,
324 loproc = 0x70000000, // Processor-specific use
325 hiproc = 0x7FFFFFFF,
326};
327
328std::string
329to_string(pt v);
330
331// Segment attributes
332enum class pf : ElfTypes::Word
333{
334 x = 0x1, // Execute permission
335 w = 0x2, // Write permission
336 r = 0x4, // Read permission
337 maskos = 0x00FF0000, // Environment-specific use
338 maskproc = 0xFF000000, // Processor-specific use
339};
340
341std::string
342to_string(pf v);
343
344static inline constexpr pf operator&(pf a, pf b)
345{
346 return (pf)((std::uint64_t)a & (std::uint64_t)b);
347}
348
349static inline constexpr pf operator|(pf a, pf b)
350{
351 return (pf)((std::uint64_t)a | (std::uint64_t)b);
352}
353
354static inline constexpr pf operator^(pf a, pf b)
355{
356 return (pf)((std::uint64_t)a ^ (std::uint64_t)b);
357}
358
359static inline constexpr pf operator~(pf a)
360{
361 return (pf)~((std::uint64_t)a);
362}
363
364static inline pf& operator&=(pf &a, pf b)
365{
366 a = a & b;
367 return a;
368}
369
370static inline pf& operator|=(pf &a, pf b)
371{
372 a = a | b;
373 return a;
374}
375
376static inline pf& operator^=(pf &a, pf b)
377{
378 a = a ^ b;
379 return a;
380}
381
382// Program header (ELF32 figure 2-1, ELF64 figure 6)
383template<typename E = Elf64, byte_order Order = byte_order::native>
384struct Phdr;
385
386template<byte_order Order>
387struct Phdr<Elf32, Order>
388{
389 typedef Elf32 types;
390 static const byte_order order = Order;
391
392 pt type; // Type of segment
393 Elf32::Off offset; // Offset in file
394 Elf32::Addr vaddr; // Virtual address in memory
395 Elf32::Addr paddr; // Reserved
396 Elf32::Word filesz; // Size of segment in file
397 Elf32::Word memsz; // Size of segment in memory
398 pf flags; // Segment attributes
399 Elf32::Word align; // Alignment of segment
400
401 template<typename E2>
402 void from(const E2 &o)
403 {
404 type = swizzle(o.type, o.order, order);
405 offset = swizzle(o.offset, o.order, order);
406 vaddr = swizzle(o.vaddr, o.order, order);
407 paddr = swizzle(o.paddr, o.order, order);
408 filesz = swizzle(o.filesz, o.order, order);
409 memsz = swizzle(o.memsz, o.order, order);
410 flags = swizzle(o.flags, o.order, order);
411 align = swizzle(o.align, o.order, order);
412 }
413};
414
415template<byte_order Order>
416struct Phdr<Elf64, Order>
417{
418 typedef Elf64 types;
419 static const byte_order order = Order;
420
421 pt type; // Type of segment
422 pf flags; // Segment attributes
423 Elf64::Off offset; // Offset in file
424 Elf64::Addr vaddr; // Virtual address in memory
425 Elf64::Addr paddr; // Reserved
426 Elf64::Xword filesz; // Size of segment in file
427 Elf64::Xword memsz; // Size of segment in memory
428 Elf64::Xword align; // Alignment of segment
429
430 template<typename E2>
431 void from(const E2 &o)
432 {
433 type = swizzle(o.type, o.order, order);
434 offset = swizzle(o.offset, o.order, order);
435 vaddr = swizzle(o.vaddr, o.order, order);
436 paddr = swizzle(o.paddr, o.order, order);
437 filesz = swizzle(o.filesz, o.order, order);
438 memsz = swizzle(o.memsz, o.order, order);
439 flags = swizzle(o.flags, o.order, order);
440 align = swizzle(o.align, o.order, order);
441 }
442};
443
444// Symbol bindings (ELF32 figure 1-16, ELF64 table 14)
445enum class stb : unsigned char
446{
447 local = 0, // Not visible outside the object file
448 global = 1, // Global symbol
449 weak = 2, // Global scope, but with lower
450 // precedence than global symbols
451 loos = 10, // Environment-specific use
452 hios = 12,
453 loproc = 13, // Processor-specific use
454 hiproc = 15,
455};
456
457std::string
458to_string(stb v);
459
460// Symbol types (ELF32 figure 1-17, ELF64 table 15)
461enum class stt : unsigned char
462{
463 notype = 0, // No type (e.g., absolute symbol)
464 object = 1, // Data object
465 func = 2, // Function entry point
466 section = 3, // Symbol is associated with a section
467 file = 4, // Source file associated with the
468 // object file
469 loos = 10, // Environment-specific use
470 hios = 12,
471 loproc = 13, // Processor-specific use
472 hiproc = 15,
473};
474
475std::string
476to_string(stt v);
477
478// Symbol table (ELF32 figure 1-15, ELF64 figure 4)
479template<typename E = Elf64, byte_order Order = byte_order::native>
480struct Sym;
481
482template<byte_order Order>
483struct Sym<Elf32, Order>
484{
485 typedef Elf32 types;
486 static const byte_order order = Order;
487
488 Elf32::Word name; // Symbol name (strtab offset)
489 Elf32::Addr value; // Symbol value (address)
490 Elf32::Word size; // Size of object
491 unsigned char info; // Type and binding attributes
492 unsigned char other; // Reserved
493 shn shnxd; // Section table index
494
495 template<typename E2>
496 void from(const E2 &o)
497 {
498 name = swizzle(o.name, o.order, order);
499 value = swizzle(o.value, o.order, order);
500 size = swizzle(o.size, o.order, order);
501 info = o.info;
502 other = o.other;
503 shnxd = swizzle(o.shnxd, o.order, order);
504 }
505
506 stb binding() const
507 {
508 return (stb)(info >> 4);
509 }
510
511 void set_binding(stb v)
512 {
513 info = (info & 0x0F) | ((unsigned char)v << 4);
514 }
515
516 stt type() const
517 {
518 return (stt)(info & 0xF);
519 }
520
521 void set_type(stt v)
522 {
523 info = (info & 0xF0) | (unsigned char)v;
524 }
525};
526
527template<byte_order Order>
528struct Sym<Elf64, Order>
529{
530 typedef Elf64 types;
531 static const byte_order order = Order;
532
533 Elf64::Word name; // Symbol name (strtab offset)
534 unsigned char info; // Type and binding attributes
535 unsigned char other; // Reserved
536 shn shnxd; // Section table index
537 Elf64::Addr value; // Symbol value (address)
538 Elf64::Xword size; // Size of object
539
540 template<typename E2>
541 void from(const E2 &o)
542 {
543 name = swizzle(o.name, o.order, order);
544 value = swizzle(o.value, o.order, order);
545 size = swizzle(o.size, o.order, order);
546 info = o.info;
547 other = o.other;
548 shnxd = swizzle(o.shnxd, o.order, order);
549 }
550
551 stb binding() const
552 {
553 return (stb)(info >> 4);
554 }
555
556 void set_binding(stb v)
557 {
558 info = (info & 0xF) | ((unsigned char)v << 4);
559 }
560
561 stt type() const
562 {
563 return (stt)(info & 0xF);
564 }
565
566 void set_type(stt v)
567 {
568 info = (info & 0xF0) | (unsigned char)v;
569 }
570};
571
572ELFPP_END_NAMESPACE
573
574#endif
575