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
#include <elf64_loader.h>
int8_t IsElf64(Elf64_Ehdr *elf64_header) {
// check magic numbers
if (elf64_header->e_ident[EI_MAG0] == ELFMAG0 && elf64_header->e_ident[EI_MAG1] == ELFMAG1 &&
elf64_header->e_ident[EI_MAG2] == ELFMAG2 &&
elf64_header->e_ident[EI_CLASS] == ELFCLASS64) {
return 1;
}
return 0;
}
int LoadElf64(const int file_descriptor, const char *section_name) {
Elf64_Ehdr elf64_header;
if (file_descriptor == PT_NULL || section_name == NULL) {
return EINVAL; // Invalid argument
}
// read file headers
if (read(file_descriptor, &elf64_header, sizeof(Elf64_Ehdr)) != sizeof(Elf64_Ehdr)) {
close(file_descriptor);
return EIO; // Input/output error
}
if (!IsElf64(&elf64_header)) {
return EINVAL; // Invalid argument (it's not an ELF file)
}
// jump through the header
if (lseek(file_descriptor, (off_t)elf64_header.e_phoff, SEEK_SET) == -1) {
close(file_descriptor);
return errno;
}
Elf64_Phdr program_headers[elf64_header.e_phnum]; // e_phnum - the number of program headers
size_t program_headers_size = sizeof(Elf64_Phdr) * elf64_header.e_phnum;
uint16_t program_headers_length = elf64_header.e_phnum;
if (read(file_descriptor, program_headers, program_headers_size) != program_headers_size) {
close(file_descriptor);
return errno;
}
int status_code = MapSegments(file_descriptor, program_headers, program_headers_length);
if (status_code != SUCCESS) {
close(file_descriptor);
return status_code;
}
// move ptr to the section header table starting point
if (lseek(file_descriptor, (off_t)elf64_header.e_shoff, SEEK_SET) == -1) {
close(file_descriptor);
return errno;
}
Elf64_Shdr section_headers[elf64_header.e_shnum]; // e_shnum - the number of section headers
size_t section_headers_size = sizeof(Elf64_Shdr) * elf64_header.e_shnum;
uint16_t section_headers_length = elf64_header.e_shnum;
if (read(file_descriptor, section_headers, section_headers_size) != section_headers_size) {
close(file_descriptor);
return EIO;
}
// e_shstrndx is a section number that contains the string table containing sections' names
Elf64_Shdr *section_names_header = §ion_headers[elf64_header.e_shstrndx];
char *section_header_ptr = NULL;
status_code = MapSection(file_descriptor, section_names_header, §ion_header_ptr);
if (status_code != SUCCESS) {
close(file_descriptor);
return status_code;
}
// find section which we want to give control
Elf64_Shdr *start_section = PT_NULL;
for (uint64_t i = 0; i < section_headers_length; i++) {
if (StringEquals(section_header_ptr + section_headers[i].sh_name, section_name)) {
start_section = §ion_headers[i];
}
}
// check whether start_section is executable
if (start_section == PT_NULL || !(start_section->sh_flags & SHF_EXECINSTR)) {
close(file_descriptor);
return EINVAL;
}
close(file_descriptor);
// give control to the section
uintptr_t entry_point_as_int = (uintptr_t)start_section->sh_addr;
EntryPointFunc entry_point = (EntryPointFunc)entry_point_as_int; // NOLINT
if (entry_point != NULL) {
entry_point();
} else {
return EINVAL;
}
return 0;
}