summaryrefslogtreecommitdiff
path: root/include/elf/elf.h
blob: 512ba14f636bc6d09210040550c8c10df354963a (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
#pragma once

// ============================================================================
// elf.h - ELF format definitions
// https://refspecs.linuxbase.org/elf/elf.pdf
// https://gist.github.com/x0nu11byt3/bcb35c3de461e5fb66173071a2379779
// https://docs.oracle.com/cd/E19683-01/816-1386/6m7qcoblh/index.html
// ============================================================================

#include <stdint.h>

/* ELF Types */
#pragma message("TODO: describe ELF types from specification")

// ============================================================================
// =================================== ELF Header =============================
// ============================================================================
#define EI_NIDENT (16)

/* e_ident offset (https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#ELF_header) */
#define EI_MAG0         0
#define EI_MAG1         1
#define EI_MAG2         2
#define EI_MAG3         3
#define EI_CLASS        4
#define EI_DATA         5
#define EI_VERSION      6
#define EI_OSABI        7
#define EI_ABIVERSION   8
#define EI_PAD          9

/* ELF Magic value */
#define ELF_MAGIC 0x464C457F  // "\x7FELF" little-endian

/* ELF Class */
#define ELFCLASS32   0x1
#define ELFCLASS64   0x2

/* Data format: or LSB(Least Significant Bit, little-endian) or MSB(Most Significant Bit, big-endian) */
#define ELFDATA2LSB  0x1
#define ELFDATA2MSB  0x2

/* ELF version */
#define ELFVERSION   0x1

/* Target ABI */
#define ELFABISYSTEMV   0x00
#define ELFABIHPUX      0x01
#define ELFABINETBSD    0x02
#define ELFABILINUX     0x03
#define ELFABIGNUHURD   0x04
#define ELFABISOLARIS   0x06
#define ELFABIAIX       0x07
#define ELFABIIRIX      0x08
#define ELFABIFREEBSD   0x09
#define ELFABITRU64     0x0A
#define ELFABINM        0x0B
#define ELFABIOPENBSD   0x0C
#define ELFABIOPENVMS   0x0D
#define ELFABINSKERNEL  0x0E
#define ELFABIAROS      0x0F
#define ELFABIFENIXOS   0x10
#define ELFABICLOUDABI  0x11
#define ELFABISTOPENVOS 0x12

/* ABI version */
#pragma message("TODO: do something with ABI version")
/* Currently i don't use ABI version */

/* Object File Types, e_type field */
#define ET_NONE     0x0    /* Unknown */
#define ET_REL      0x1    /* Relocatable. (output of gcc -c). Contains sections + symbol tables + relocations. No program header */
#define ET_EXEC     0x2    /* Executable. Statically-linked executable with fixed virtual addresses. Has program headers. */
#define ET_DYN      0x3    /* Shared object. Shared library or PIE executable. Postitoin-independent, relocated at load time. */
#define ET_CORE     0x4    /* Core dump. Process memory image for post-mortem debugging */
#define ET_LOOS     0xFE00 /* Reserved inclusive range. Operating system specific */
#define ET_HIOS     0xFEFF /* Reserved inclusive range. Operating system specific */
#define ET_LOPROC   0xFF00 /* Reserved inclusive range. Processor specific */
#define ET_HIPROC   0xFFFF /* Reserved inclusive range. Processor specific */

/* Arch types, e_machine field */
#pragma message("TODO: add other architecture defines, copy from github")
#define EM_X86      0x03
#define EM_X86_64   0x3E
#define EM_ARM      0x28 /* up to Armv7/AArch32 */
#define EM_AARCH64  0xB7 /* Armv8/AArch64 */

/* Version value, e_version field */
#define EV_NONE     0x00
#define EV_CURRENT  0x01
#define EV_NUM      0x02

/* Other header fields: 
    e_entry: Memory address of the entry point.
    e_phoff: Pointer to the start of the program header table.
    e_shoff: Pointer to the start of section header table.
    e_flags: Interpretation of this field depends on the target arch.
    e_ehsize: Contains the size of header (normally 64 bytes for 64-bit and 52 Bytes for 32-bit)
    e_phentsize: Contains the size of program header table entry. Or 0x20 (for 32-bit) or 0x38 (for 64-bit).
    e_phnum: Contains the number of entries in the program header table.
    e_shentsize: Contains the size of a section header table entry. Or 0x28 (for 32-bit) or 0x40 (for 64-bit)
    e_shnum: Contains the number of entries in the section header table.
    e_shstrndx: Contains index of the section header table entry, that contains the section names.
*/

/* ELF header (atm only for 64 bit) */
#pragma message("TODO: add elf header for 32 bit")
struct Elf64_Ehdr {
    uint8_t  e_ident[EI_NIDENT];
    uint16_t e_type;
    uint16_t e_machine;
    uint32_t e_version;
    uint64_t e_entry;
    uint64_t e_phoff;
    uint64_t e_shoff;
    uint32_t e_flags;
    uint16_t e_ehsize;
    uint16_t e_phentsize;
    uint16_t e_phnum;
    uint16_t e_shentsize;
    uint16_t e_shnum;
    uint16_t e_shstrndx;
};

// ============================================================================
// =================================== Program Header =========================
// ============================================================================

/* Type, p_type field */
#define PT_NULL         0x00000000 /* Program header table entry unused */
#define PT_LOAD         0x00000001 /* Loadable segment */
#define PT_DYNAMIC      0x00000002 /* Dynamic linking information */
#define PT_INTERP       0x00000003 /* Interpreter information */
#define PT_NOTE         0x00000004 /* Auxiliary information */
#define PT_SHLIB        0x00000005 /* Reserved */
#define PT_PHDR         0x00000006 /* Segment containing program header table itself */
#define PT_TLS          0x00000007 /* Thread-Local Storage template */
#define PT_NUM          0x00000008 /* Number of defined types */
#define PT_LOOS         0x60000000 /* Reserved inclusive range. Operating system specific: */
#define PT_GNU_EH_FRAME	0x6474e550	/* GCC .eh_frame_hdr segment */
#define PT_GNU_STACK	0x6474e551	/* Indicates stack executability */
#define PT_GNU_RELRO	0x6474e552	/* Read-only after relocation */
#define PT_LOSUNW	    0x6ffffffa
#define PT_SUNWBSS	    0x6ffffffa	/* Sun Specific segment */
#define PT_SUNWSTACK	0x6ffffffb	/* Stack segment */
#define PT_HISUNW	    0x6fffffff
#define PT_HIOS         0x6FFFFFFF /* Reserved inclusive range. Operating system specific end*/
#define PT_LOPROC       0x70000000 /* Reserved inclusive range. Processor specific */
#define PT_HIPROC       0x7FFFFFFF /* Reserved inclusive range. Processor specific */

/* Flags, p_flags 64-bit field */
#define PF_X        0x1 /* Executable segment */
#define PF_W        0x2 /* Writeable segment */
#define PF_R        0x4 /* Readable segment */
#define PF_MASKOS   0x0FF00000 /* OS-specific */
#define PF_MASKPROC 0xF0000000 /* Processor-specific */

/* Other Program Header fields:
    p_offset: Offset of the segment in the file image.
    p_vaddr: Virtual address of the segment in memory.
    p_paddr: On systems where physical address is relevant, reserved for segment's physical address.
    p_filesz: Size in bytes of the segment in the file image. May be 0.
    p_memsz: Size in bytes of the segment in memory. May be 0.
    p_flags: 32-bit flags (don't exist on 64 bit header)
    p_align: 0 and 1 specify no alignment. Otherwise should be a positive, integral power of 2, with p_vaddr equating p_offset modules p_align
*/

/* Elf64 Program Header */
struct Elf64_Phdr {
    uint32_t p_type;
    uint32_t p_flags;
    uint64_t p_offset;
    uint64_t p_vaddr;
    uint64_t p_paddr;
    uint64_t p_filesz;
    uint64_t p_memsz;
    uint64_t p_align;
};

// ============================================================================
// =================================== Section Header =============================
// ============================================================================

/* Section Header Type, sh_type field  */
#define SHT_NULL            0x0 /* Section header table entry unused. First entry in the section table must be SHT_NULL according the stanard */
#define SHT_PROGBITS        0x1 /* Program data */
#define SHT_SYMTAB          0x2 /* Symbol table */
#define SHT_STRTAB          0x3 /* String table */
#define SHT_RELA            0x4 /* Relocation entries with addends */
#define SHT_HASH            0x5 /* Symbol hash table */
#define SHT_DYNAMIC         0x6 /* Dynamic linking information */
#define SHT_NOTE            0x7 /* Notes */
#define SHT_NOBITS          0x8 /* Program space with no data (bss) */
#define SHT_REL             0x9 /* Relocation entries, no addends */
#define SHT_SHLIB           0x0A /* Reserved */
#define SHT_DYNSYM          0x0B /* Dynamic linker symbol table */
#define SHT_INIT_ARRAY      0x0E /* Array of constructors */
#define SHT_FINI_ARRAY      0x0F /* Array of destructors */
#define SHT_PREINIT_ARRAY   0x10 /* Array of pre-constructors */
#define SHT_GROUP           0x11 /* Section group */
#define SHT_SYMTAB_SHNDX    0x12 /* Extended section indices */
#define SHT_NUM             0x13 /* Number of defined types */
#define SHT_LOOS            0x60000000 /* Start OS-specific */
#define SHT_GNU_ATTRIBUTES  0x6ffffff5	/* Object attributes.  */
#define SHT_GNU_HASH	    0x6ffffff6	/* GNU-style hash table.  */
#define SHT_GNU_LIBLIST	    0x6ffffff7	/* Prelink library list */
#define SHT_CHECKSUM	    0x6ffffff8	/* Checksum for DSO content.  */
#define SHT_LOSUNW	        0x6ffffffa	/* Sun-specific low bound.  */
#define SHT_SUNW_move	    0x6ffffffa
#define SHT_SUNW_COMDAT     0x6ffffffb
#define SHT_SUNW_syminfo    0x6ffffffc
#define SHT_GNU_verdef	    0x6ffffffd	/* Version definition section.  */
#define SHT_GNU_verneed	    0x6ffffffe	/* Version needs section.  */
#define SHT_GNU_versym	    0x6fffffff	/* Version symbol table.  */
#define SHT_HISUNW	        0x6fffffff	/* Sun-specific high bound.  */
#define SHT_HIOS	        0x6fffffff	/* End OS-specific type */
#define SHT_LOPROC	        0x70000000	/* Start of processor-specific */
#define SHT_HIPROC	        0x7fffffff	/* End of processor-specific */
#define SHT_LOUSER	        0x80000000	/* Start of application-specific */
#define SHT_HIUSER	        0x8fffffff	/* End of application-specific */

/* Section Header flags, sh_flags field */
#define SHF_WRITE               0x1 /*Writable*/
#define SHF_ALLOC               0x2 /*Occupies memory during execution*/
#define SHF_EXECINSTR           0x4 /*Executable*/
#define SHF_MERGE               0x10 /*Might be merged*/
#define SHF_STRINGS             0x20 /*Contains null-terminated strings*/
#define SHF_INFO_LINK           0x40 /*'sh_info' contains SHT index*/
#define SHF_LINK_ORDER          0x80 /*Preserve order after combining*/
#define SHF_OS_NONCONFORMING    0x100 /*Non-standard OS specific handling required*/
#define SHF_GROUP               0x200 /*Section is member of a group*/
#define SHF_TLS                 0x400 /*Section hold thread-local data*/
#define SHF_COMPRESSED          0x800 /*Section with compressed data*/
#define SHF_MASKOS              0x0FF00000 /*OS-specific*/
#define SHF_MASKPROC            0xF0000000 /*Processor-specific*/
#define SHF_ORDERED             0x4000000 /*Special ordering requirement (Solaris)*/
#define SHF_EXCLUDE             0x8000000 /*Section is excluded unless referenced or allocated (Solaris)*/

/* Other Section Header fields:
    sh_name: An offset to a string in the .shstrab section that represents the name of this section. Zero means no name.
    sh_addr: Virtual address of the section in memory, for sections that are loaded.
    sh_offset: Offset of the section in the file image.
    sh_size: Size in bytes of the section. May be 0.
    sh_link: Contains the section index of an associated section. This field is used for several purposes, depending on the type of section.
    sh_info: Contains extra information about the section. This field is used for several purposes, depending on the type of section.
    sh_addralign: Contains the required alignment of the section. This field must be a power of two.
    sh_entsize: Contains the size, in bytes, of each entry, for sections that contain fixed-size entries. Otherwise, this field contains zero.
*/
/*
    The most common ELF sections:
    .text - contains executable code. Packed with Read and Execute flags. Load only one times. Can't be changed.
    .data - initalized data. Read and Write flags.
    .rodata - initalized read only data. Read flag.
    .bss - unititlized data. Read and Write flags.
    other sections you can see here: https://gist.github.com/x0nu11byt3/bcb35c3de461e5fb66173071a2379779#sections

    Also, there is something like "group of sections" (readelf -g), but it's very rare.
*/

/* Elf64 Section Header */
struct Elf64_Shdr {
    uint32_t sh_name;
    uint32_t sh_type;
    uint64_t sh_flags;
    uint64_t sh_addr;
    uint64_t sh_offset;
    uint64_t sh_size;
    uint32_t sh_link;
    uint32_t sh_info;
    uint64_t sh_addralign;
    uint64_t sh_entsize;
};

// ============================================================================
// =================================== Symbols ================================
// ============================================================================
// https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-79797/index.html
#pragma message("TODO: do")

/*  Symbol fields:
    st_name: Symbol name
    st_info: Symbol type and binding. It is calculated using macros
    st_other: Symbol visibility.
    st_shndx: Section index.
    st_value: Symbol value.
    st_size: Symbol size;
*/

/* Symbol struct */
struct Elf64_Sym {
    uint32_t st_name;
    uint8_t st_info;
    uint8_t st_other;
    uint16_t st_shndx;
    uint64_t st_value;
    uint64_t st_size;
};


// ============================================================================
// =================================== ELF Page size ==========================
// ============================================================================
#define ELF_PAGE_SIZE   0x1000
#define ELF_PAGE_MASK   (ELF_PAGE_SIZE - 1)

// ============================================================================
// =================================== ELF Load Result ========================
// ============================================================================
// ATM it uses in efi_elf_parser.cpp

/* Error codes for ElfLoadResult.error */
#define ELF_ERR_NONE           0  /* success */
#define ELF_ERR_FILE_TOO_SMALL 1 /* file smaller than ELF header */
#define ELF_ERR_INVALID_MAGIC  2 /* bad magic */
#define ELF_ERR_INVALID_CLASS  3 /* bad class */
#define ELF_ERR_INVALID_IDENT  4 /* bad ident */
#define ELF_ERR_INVALID_ARCH   5 /* bad machine */
#define ELF_ERR_INVALID_TYPE   6 /* bad type */
#define ELF_ERR_NO_LOAD_SEGS   7 /* no PT_LOAD segments found */
#define ELF_ERR_ALLOC_FAILED   8 /* AllocatePages failed (check efi_alloc_status) */

/* Elf Load Result object */
struct ElfLoadResult {
    uint64_t entry_point;
    uint64_t phys_base;
    uint64_t virt_base;
    uint64_t total_size;
    uint64_t efi_alloc_status; /* EFI_STATUS from AllocatePages, valid when error == ELF_ERR_ALLOC_FAILED */
    uint8_t  error;            /* ELF_ERR_* code above */
    bool     success;
};