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
|
#include <string.h>
#include <elf.h>
bool is_elf(fs_handle_t *f) {
elf_ehdr_t h;
if (file_read(f, 0, sizeof(elf_ehdr_t), (char*)&h) != sizeof(elf_ehdr_t)) return false;
return (h.e_ident[0] == 0x7F && h.e_ident[1] == 'E'
&& h.e_ident[2] == 'L' && h.e_ident[3] == 'F');
}
proc_entry_t elf_load(fs_handle_t *f, process_t* process) {
if (!is_elf(f)) return 0;
elf_ehdr_t ehdr;
if (file_read(f, 0, sizeof(elf_ehdr_t), (char*)&ehdr) != sizeof(elf_ehdr_t)) return 0;
elf_phdr_t phdr;
int i;
pagedir_t *r = get_current_pagedir();
switch_pagedir(process->pd);
// TODO : when we fail, free ressources ?
for (i = 0; i < ehdr.e_phnum; i++) {
size_t read_phdr_r =
file_read(f,
ehdr.e_phoff + i * sizeof(elf_phdr_t),
sizeof(elf_phdr_t),
(char*)&phdr);
if (read_phdr_r != sizeof(elf_phdr_t)) goto error;
if (phdr.p_type == PT_LOAD) {
if ((phdr.p_flags & PF_W) || !(file_get_mode(f) & FM_MMAP)) {
bool mmap_ok = mmap(process, (void*)phdr.p_vaddr, phdr.p_memsz,
((phdr.p_flags & PF_R) ? MM_READ : 0) | MM_WRITE);
if (!mmap_ok) goto error;
size_t read_r = file_read(f, phdr.p_offset, phdr.p_filesz, (char*)phdr.p_vaddr);
if (read_r != phdr.p_filesz) goto error;
if (phdr.p_memsz > phdr.p_filesz) {
memset((char*)phdr.p_vaddr + phdr.p_filesz, 0, phdr.p_memsz - phdr.p_filesz);
}
if (!(phdr.p_flags & PF_W)) {
bool mchmap_ok = mchmap(process, (void*)phdr.p_vaddr,
((phdr.p_flags & PF_R) ? MM_READ : 0));
if (!mchmap_ok) goto error;
}
} else {
if (phdr.p_filesz != phdr.p_memsz) {
dbg_printf("Strange ELF file...\n");
}
bool mmap_ok = mmap_file(process,
f, phdr.p_offset,
(void*)phdr.p_vaddr, phdr.p_memsz,
((phdr.p_flags & PF_R) ? MM_READ : 0) | ((phdr.p_flags & PF_X) ? MM_EXEC : 0));
if (!mmap_ok) goto error;
}
}
}
switch_pagedir(r);
return (proc_entry_t)ehdr.e_entry;
error:
switch_pagedir(r);
return 0;
}
/* vim: set ts=4 sw=4 tw=0 noet :*/
|