1 /// Copyright: Copyright (c) 2020 Andrey Penechko.
2 /// License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
3 /// Authors: Andrey Penechko.
4 
5 /// Resources:
6 /// - https://www.muppetlabs.com/~breadbox/software/ELF.txt
7 /// - ELF-64 Object File Format: Version 1.5 Draft 2, May 27, 1998
8 /// - http://www.skyfree.org/linux/references/ELF_Format.pdf
9 /// - https://github.com/aspieln3r/spergland/wiki/ELF-File-:-short-summary
10 /// - https://refspecs.linuxbase.org/elf/gabi4+/ch4.eheader.html
11 
12 /// An ELF object file consists of the following parts:
13 /// * File header, which must appear at the beginning of the file.
14 /// * Section table, required for relocatable files, and optional for loadable files.
15 /// * Program header table, required for loadable files, and optional for
16 ///   relocatable files. This table describes the loadable segments and other
17 ///   data structures required for loading a program or dynamically-linked
18 ///   library in preparation for execution.
19 /// * Contents of the sections or segments, including loadable data, relocations,
20 ///   and string and symbol tables.
21 module vox.be.elf64;
22 
23 /// The file header is located at the beginning of the file, and is used to locate the other parts of the file.
24 struct Elf64Header {
25 	char[4] magic = "\x7FELF";
26 	ElfObjectFileClass file_class = ElfObjectFileClass.ELFCLASS64;
27 	ElfDataEncoding data_encoding = ElfDataEncoding.ELFDATA2LSB;
28 	ubyte file_version = 1; // Object file format version, always 1
29 	ElfOsAbi os_abi; // Identifies the operating system and ABI for which the object is prepared
30 	// Specifies version of the ABI in os_abi field
31 	// For applications conforming to the System V ABI, third edition, this field should contain 0.
32 	ubyte abi_version = 0;
33 	ubyte[7] pad;
34 
35 	ElfObjectFileType file_type; // Object file type
36 	ElfMachineType machine;   // Machine type. These values are defined in the processor-specific supplements.
37 	uint      _version = 1; // Object file format version
38 	// Contains the virtual address of the program entry point. If there is no entry point, this field contains zero.
39 	ulong     entry;     // Entry point address
40 	ulong     phoff = 64; // Program header file offset in bytes
41 	ulong     shoff;     // Section header file offset in bytes
42 	uint      flags;     // Processor-specific flags
43 	ushort    ehsize = 64; // ELF header size in bytes
44 	ushort    phentsize = 56; // Program header table single entry size in bytes.
45 	ushort    phnum;     // Program header table number of entries.
46 	ushort    shentsize = 64; // Section header table single entry size in bytes.
47 	ushort    shnum;     // Section header table number of entries.
48 	// Contains the section header table index of the section containing
49 	// the section name string table. If there is no section name string
50 	// table, this field has the value SHN_UNDEF (0)
51 	ushort    shstrndx;  // String table index
52 }
53 static assert(Elf64Header.sizeof == 64);
54 
55 // Object File Classes, identifies the class of the object file, or its capacity.
56 enum ElfObjectFileClass : ubyte {
57 	ELFCLASSNONE = 0, /// Invalid class
58 	ELFCLASS32 = 1, /// 32-bit objects
59 	ELFCLASS64 = 2, /// 64-bit objects
60 }
61 
62 // Data Encodings
63 enum ElfDataEncoding : ubyte {
64 	ELFDATA2LSB = 1, /// Object file data structures are little-endian
65 	ELFDATA2MSB = 2, /// Object file data structures are big-endian
66 }
67 
68 // Operating System and ABI Identifiers,
69 enum ElfOsAbi : ubyte {
70 	ELFOSABI_SYSV = 0, /// System V ABI
71 	ELFOSABI_HPUX = 1, /// HP-UX operating system
72 	ELFOSABI_STANDALONE = 255, /// Standalone (embedded) application
73 }
74 
75 // Object File Types
76 enum ElfObjectFileType : ushort {
77 	ET_NONE = 0, /// No file type
78 	ET_REL  = 1, /// Relocatable object file
79 	ET_EXEC = 2, /// Executable file
80 	ET_DYN  = 3, /// Shared object file
81 	ET_CORE = 4, /// Core file
82 	ET_LOOS = 0xFE00, /// Environment-specific use
83 	ET_HIOS = 0xFEFF, ///
84 	ET_LOPROC = 0xFF00, /// Processor-specific use
85 	ET_HIPROC = 0xFFFF, ///
86 }
87 
88 enum ElfMachineType : ushort {
89 	x86 = 0x03,    /// x86
90 	x86_64 = 0x3E, /// amd64
91 	arm = 0x28,
92 	arm64 = 0xB7,  /// aarch64
93 	riscv = 0xF3,  /// RISC-V
94 }
95 
96 // Section index 0, and indices in the range 0xFF00–0xFFFF are reserved for special purposes.
97 // The first entry in the section header table (with an index of 0) is reserved, and must contain all zeroes.
98 enum ElfSectionIndicies : ushort {
99 	SHN_UNDEF = 0, /// Used to mark an undefined or meaningless section reference
100 	SHN_LOPROC = 0xFF00, /// Processor-specific use
101 	SHN_HIPROC = 0xFF1F,
102 	SHN_LOOS = 0xFF20, /// Environment-specific use
103 	SHN_HIOS = 0xFF3F,
104 	SHN_ABS = 0xFFF1, /// Indicates that the corresponding reference is an absolute value
105 	SHN_COMMON = 0xFFF2, /// Indicates a symbol that has been declared as a common block (Fortran COMMON or C tentative declaration)
106 }
107 
108 struct Elf64SectionHeader {
109 	uint  sh_name;      /// Section name
110 	uint  sh_type;      /// Section type
111 	ulong sh_flags;     /// Section attributes
112 	ulong sh_addr;      /// Virtual address in memory
113 	ulong sh_offset;    /// Offset in file
114 	ulong sh_size;      /// Size of section
115 	uint  sh_link;      /// Link to other section
116 	uint  sh_info;      /// Miscellaneous information
117 	ulong sh_addralign; /// Address alignment boundary
118 	ulong sh_entsize;   /// Size of entries, if section has table
119 }
120 
121 struct Elf64ProgramHeader {
122 	Elf64SegmentType type; /// Type of segment
123 	uint  flags;  /// Segment attributes (set of Elf64SegmentAttributes)
124 	ulong offset; /// Offset in file
125 	ulong vaddr;  /// Virtual address in memory
126 	ulong paddr;  /// Reserved
127 	ulong filesz; /// Size of segment in file
128 	ulong memsz;  /// Size of segment in memory
129 	ulong alignment; /// Alignment of segment
130 }
131 
132 enum Elf64SegmentType : uint {
133 	PT_NULL = 0, /// Unused entry
134 	PT_LOAD = 1, /// Loadable segment
135 	PT_DYNAMIC = 2, /// Dynamic linking tables
136 	/// If PT_INTERP segment is added, then PT_DYNAMIC must be present too
137 	/// Otherwise it is invalid executable
138 	PT_INTERP = 3, /// Program interpreter path name
139 	PT_NOTE = 4, /// Note sections
140 	PT_SHLIB = 5, /// Reserved
141 	PT_PHDR = 6, /// Program header table
142 	PT_TLS = 7, /// Thread Local Storage http://www.sco.com/developers/gabi/latest/ch5.pheader.html#tls
143 	PT_LOOS = 0x6000_0000, /// Environment-specific use
144 	PT_HIOS = 0x6FFF_FFFF,
145 	PT_LOPROC = 0x7000_0000, /// Processor-specific use
146 	PT_HIPROC = 0X7FFF_FFFF,
147 	/// The array element specifies the location and size of the
148 	/// exception handling information as defined by the .eh_frame_hdr section.
149 	PT_GNU_EH_FRAME = 0X6474E550,
150 	/// The p_flags member specifies the permissions on the segment containing the stack and
151 	/// is used to indicate wether the stack should be executable. The absense of this header
152 	/// indicates that the stack will be executable.
153 	PT_GNU_STACK = 0X6474E551,
154 	/// The array element specifies the location and size of a segment which may be made
155 	/// read-only after relocation shave been processed.
156 	PT_GNU_RELRO = 0X6474E552,
157 }
158 
159 enum Elf64SegmentAttributes : uint {
160 	EXECUTE = 0x1, /// Execute permission
161 	WRITE = 0x2, /// Write permission
162 	READ = 0x4, /// Read permission
163 	PF_MASKOS = 0x00FF_0000, /// These flag bits are reserved for environment-specific use
164 	PF_MASKPROC = 0xFF00_0000, /// These flag bits are reserved for processor-specific use
165 }