AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
elf.c
Go to the documentation of this file.
1
9
10
11#include <core/system.h>
12#include <core/panic.h>
13#include <core/arch.h>
14
15#include <sys/proc.h>
16#include <sys/sched.h>
17#include <sys/elf.h>
18#include <mm/vm.h>
19
20/* The kernel runs only programs of its own class and machine (the
21 * machine comes from the architecture's config.h). */
22#ifndef ELF_MACHINE
23#error "the architecture's config.h has no ELF_MACHINE"
24#endif
25
26#if ARCH_BITS==32
27#define ELF_CLASS ELFCLASS32
28typedef struct elf32_hdr elf_hdr;
29typedef struct elf32_phdr elf_phdr;
30#else
31#define ELF_CLASS ELFCLASS64
32typedef struct elf64_hdr elf_hdr;
33typedef struct elf64_phdr elf_phdr;
34#endif
35
42static int binfmt_elf_load_segments(struct proc *proc, struct vnode *vnode)
43{
44 int err = 0;
45
46 struct vm_space *vm_space = &proc->vm_space;
47
48 elf_hdr hdr;
49
50 if (vfs_read(vnode, 0, sizeof(hdr), &hdr) != sizeof(hdr))
51 goto e_inval;
52
53 if (hdr.e_ident[EI_CLASS] != ELF_CLASS || hdr.e_machine != ELF_MACHINE)
54 goto e_inval;
55
56 if (hdr.e_phentsize < sizeof(elf_phdr))
57 goto e_inval;
58
59 uintptr_t proc_heap = 0;
60 size_t offset = hdr.e_phoff;
61
62 for (int i = 0; i < hdr.e_phnum; ++i) {
63 elf_phdr phdr;
64
65 if (vfs_read(vnode, offset, sizeof(phdr), &phdr) != sizeof(phdr))
66 goto e_inval;
67
68 if (phdr.p_type == PT_LOAD) {
69 vaddr_t base = phdr.p_vaddr;
70 size_t filesz = phdr.p_filesz;
71 size_t memsz = phdr.p_memsz;
72 size_t off = phdr.p_offset;
73
74 /* the segment must lie entirely below the user stack (the
75 * kernel writes to it below to clear the bss), its file offset
76 * must be congruent to its address modulo the page size, and
77 * the segments must be sorted and not overlap */
78 if (filesz > memsz ||
79 base + memsz < base ||
80 PAGE_ROUND(base + memsz) > USER_STACK_BASE ||
81 PAGE_ROUND(base + memsz) < base + memsz ||
82 (off & PAGE_MASK) != (base & PAGE_MASK) ||
83 PAGE_ALIGN(base) < proc_heap)
84 goto e_inval;
85
86 /* start the mapping on a page boundary */
87 if (base & PAGE_MASK) {
88 memsz += base & PAGE_MASK;
89 filesz += base & PAGE_MASK;
90 off -= base & PAGE_MASK;
91 base = PAGE_ALIGN(base);
92 }
93
94 /* map whole pages */
95 memsz = PAGE_ROUND(memsz);
96
97 struct vm_entry *vm_entry = vm_entry_new();
98 if (!vm_entry) goto e_nomem;
99
100 vm_entry->base = base;
101 vm_entry->size = memsz;
102 vm_entry->off = off;
103
104 /* the segment's permissions */
105 vm_entry->flags |= phdr.p_flags & PF_R? VM_UR : 0;
106 vm_entry->flags |= phdr.p_flags & PF_W? VM_UW : 0;
107 vm_entry->flags |= phdr.p_flags & PF_X? VM_UX : 0;
108
109 /* (a segment may be both writable and executable: W^X isn't
110 * enforced) */
111
113
114 if (!vm_entry->qnode) {
116 goto e_nomem;
117 }
118
120
121 if (!vm_entry->vm_object)
122 goto e_nomem;
123
124 if (vm_entry->flags & VM_UW)
126
128
129 if (base + memsz > proc_heap)
130 proc_heap = base + memsz;
131
132 /* the bss: the part of the segment past the file's data, which
133 * starts zeroed */
134 if (phdr.p_memsz != phdr.p_filesz) {
135 vaddr_t bss = base + filesz;
136
137 vaddr_t bss_init_end = PAGE_ROUND(base + filesz);
138
139 if (vm_entry->base + vm_entry->size > bss_init_end) {
140 size_t sz = bss_init_end - vm_entry->base;
141
142 struct vm_entry *split = vm_entry_new();
143 if (!split) goto e_nomem;
144
145 split->base = bss_init_end;
146 split->size = vm_entry->size - sz;
147 split->flags = vm_entry->flags;
148 split->off = 0;
149
150 split->qnode = enqueue(&vm_space->vm_entries, split);
151
152 if (!split->qnode) {
153 kfree(split);
154 goto e_nomem;
155 }
156
157 vm_entry->size = sz;
158 }
159
160 /* zero the rest of the last page that has file data (the
161 * write faults the page in); only for a writable segment,
162 * since a read-only page is shared with the file */
163 if (vm_entry->flags & VM_UW)
164 memset((void *) bss, 0, bss_init_end-bss);
165 }
166 }
167
168 offset += hdr.e_phentsize;
169 }
170
171 proc->heap_start = proc_heap;
172 proc->heap = proc_heap;
173 proc->entry = hdr.e_entry;
174
175 return err;
176
177e_nomem:
178 err = -ENOMEM;
179 goto error;
180
181e_inval:
182 err = -EINVAL;
183 goto error;
184
185error:
186 /* the caller releases the mappings already added */
187 return err;
188}
189
190
200{
201 struct elf32_hdr hdr;
202
203 if (vfs_read(vnode, 0, sizeof(hdr), &hdr) != sizeof(hdr))
204 return -ENOEXEC;
205
206 /* the magic number, and the class and machine (`e_machine` is at the
207 * same place in both classes' headers) */
208 if (hdr.e_ident[EI_MAG0] == ELFMAG0 &&
209 hdr.e_ident[EI_MAG1] == ELFMAG1 &&
210 hdr.e_ident[EI_MAG2] == ELFMAG2 &&
211 hdr.e_ident[EI_MAG3] == ELFMAG3 &&
212 hdr.e_ident[EI_CLASS] == ELF_CLASS &&
213 hdr.e_machine == ELF_MACHINE)
214 return 0;
215
216 return -ENOEXEC;
217}
218
227int binfmt_elf_load(struct proc *proc, const char *path __unused, struct vnode *vnode)
228{
230}
#define ELF_MACHINE
Definition config.h:12
#define USER_STACK_BASE
Definition arch.h:61
#define PAGE_MASK
Definition system.h:8
uint64_t vaddr_t
Definition mm.h:40
int binfmt_elf_check(struct vnode *vnode)
Says whether a file is an ELF program this kernel can run: its magic number, class and machine.
Definition elf.c:199
int binfmt_elf_load(struct proc *proc, const char *path, struct vnode *vnode)
Loads an ELF program into a process.
Definition elf.c:227
struct elf64_hdr elf_hdr
Definition elf.c:32
struct elf64_phdr elf_phdr
Definition elf.c:33
static int binfmt_elf_load_segments(struct proc *proc, struct vnode *vnode)
Maps the loadable segments of an ELF file into a process, and sets its entry point and the start of i...
Definition elf.c:42
#define ELF_CLASS
Definition elf.c:31
#define PF_X
Definition elf.h:127
#define PF_W
Definition elf.h:128
#define EI_MAG2
Definition elf.h:48
#define ELFMAG0
Definition elf.h:56
#define ELFMAG3
Definition elf.h:59
#define EI_MAG1
Definition elf.h:47
#define EI_CLASS
Definition elf.h:50
#define ELFMAG1
Definition elf.h:57
#define PT_LOAD
Definition elf.h:118
#define ELFMAG2
Definition elf.h:58
#define EI_MAG0
Definition elf.h:46
#define EI_MAG3
Definition elf.h:49
#define PF_R
Definition elf.h:129
struct vm_object * vm_object_vnode(struct vnode *vnode)
Gets a vnode's vm object, making it the first time.
Definition vm_object.c:31
#define PAGE_ALIGN(ptr)
Definition mm.h:9
#define PAGE_ROUND(ptr)
Definition mm.h:10
void kfree(void *)
Frees an object that kmalloc() gave.
Definition kvmem.c:146
void * memset(void *dst, int c, size_t n)
Sets n bytes to c.
Definition libc.c:23
ssize_t vfs_read(struct vnode *vnode, off_t off, size_t size, void *buf)
Reads from a vnode into a kernel buffer.
Definition read.c:52
__SIZE_TYPE__ uintptr_t
Definition stddef.h:12
An ELF32 file's header.
Definition elf.h:151
uint8_t e_ident[EI_NIDENT]
Definition elf.h:152
elf32_half e_machine
Definition elf.h:154
An ELF32 program header: a segment to load.
Definition elf.h:228
An ELF64 file's header.
Definition elf.h:249
uint8_t e_ident[EI_NIDENT]
Definition elf.h:250
elf64_half e_machine
Definition elf.h:252
elf64_off e_phoff
Definition elf.h:255
elf64_addr e_entry
Definition elf.h:254
elf64_half e_phentsize
Definition elf.h:259
elf64_half e_phnum
Definition elf.h:260
An ELF64 program header: a segment to load.
Definition elf.h:267
elf64_xword p_filesz
Definition elf.h:273
elf64_addr p_vaddr
Definition elf.h:271
elf64_word p_type
Definition elf.h:268
elf64_word p_flags
Definition elf.h:269
elf64_xword p_memsz
Definition elf.h:274
elf64_off p_offset
Definition elf.h:270
A process.
Definition proc.h:75
struct vm_space vm_space
its address space
Definition proc.h:129
uintptr_t heap_start
where its heap starts, and where it ends now (sbrk())
Definition proc.h:122
uintptr_t heap
Definition proc.h:123
uintptr_t entry
its program's entry point
Definition proc.h:126
A mapping (map entry): a range of an address space, its permissions, and where its pages come from.
Definition vm.h:66
uint32_t flags
its permissions and flags (VM_*)
Definition vm.h:78
size_t off
where the mapping starts in its object
Definition vm.h:87
vaddr_t base
where the mapping starts in its address space
Definition vm.h:72
struct vm_object * vm_object
its object: what its other pages come from (a file)
Definition vm.h:84
struct qnode * qnode
its node in its address space's list of mappings
Definition vm.h:90
size_t size
its size
Definition vm.h:75
An address space: its mappings, and its page tables.
Definition vm.h:25
struct queue vm_entries
its mappings (map entries), in address order
Definition vm.h:30
A file in memory (a vnode): what its inode says, and the kernel's own state.
Definition vfs.h:113
#define VM_COPY
to be copied before it's written to
Definition vm.h:47
#define VM_UR
user read
Definition vm.h:41
struct vm_entry * vm_entry_new(void)
Makes a new, empty map entry.
Definition vm_entry.c:18
#define VM_UX
user execute
Definition vm.h:43
void vm_object_incref(struct vm_object *vm_object)
Adds a reference to a vm object: one more mapping of it.
Definition vm_object.c:25
#define VM_UW
user write
Definition vm.h:42