1204be4e1f8e0f760b48c03b2ca5e3d333a4d711
[lunaix-os.git] / lunaix-os / kernel / exe / elf32 / ldelf32.c
1 #include <lunaix/exebi/elf32.h>
2 #include <lunaix/load.h>
3 #include <lunaix/mm/mmap.h>
4 #include <lunaix/mm/page.h>
5 #include <lunaix/spike.h>
6
7 int
8 elf32_smap(struct load_context* ldctx,
9            const struct elf32* elf,
10            struct elf32_phdr* phdre)
11 {
12     struct v_file* elfile = (struct v_file*)elf->elf_file;
13
14     assert(PG_ALIGNED(phdre->p_offset));
15
16     int proct = 0;
17     if ((phdre->p_flags & PF_R)) {
18         proct |= PROT_READ;
19     }
20     if ((phdre->p_flags & PF_W)) {
21         proct |= PROT_WRITE;
22     }
23     if ((phdre->p_flags & PF_X)) {
24         proct |= PROT_EXEC;
25     }
26
27     struct exec_container* container = ldctx->container;
28     struct mmap_param param = { .vms_mnt = container->vms_mnt,
29                                 .pvms = &container->proc->mm,
30                                 .proct = proct,
31                                 .offset = PG_ALIGN(phdre->p_offset),
32                                 .mlen = ROUNDUP(phdre->p_memsz, PG_SIZE),
33                                 .flen = phdre->p_filesz + PG_MOD(phdre->p_va),
34                                 .flags = MAP_FIXED | MAP_PRIVATE,
35                                 .type = REGION_TYPE_CODE };
36
37     struct mm_region* seg_reg;
38     int status = mem_map(NULL, &seg_reg, PG_ALIGN(phdre->p_va), elfile, &param);
39
40     if (!status) {
41         size_t next_addr = phdre->p_memsz + phdre->p_va;
42         ldctx->end = MAX(ldctx->end, ROUNDUP(next_addr, PG_SIZE));
43         ldctx->mem_sz += phdre->p_memsz;
44     } else {
45         // we probably fucked up our process
46         terminate_proc(-1);
47     }
48
49     return status;
50 }
51
52 int
53 load_executable(struct load_context* context, const struct v_file* exefile)
54 {
55     int errno = 0;
56
57     char* ldpath = NULL;
58     struct elf32 elf;
59     struct exec_container* container = context->container;
60
61     if ((errno = elf32_openat(&elf, exefile))) {
62         goto done;
63     }
64
65     if (!elf32_check_exec(&elf)) {
66         errno = ENOEXEC;
67         goto done;
68     }
69
70     ldpath = valloc(512);
71     errno = elf32_find_loader(&elf, ldpath, 512);
72
73     if (errno < 0) {
74         goto done;
75     }
76
77     if (errno != NO_LOADER) {
78         container->argv_pp[1] = ldpath;
79
80         // close old elf
81         if ((errno = elf32_close(&elf))) {
82             goto done;
83         }
84
85         // open the loader instead
86         if ((errno = elf32_open(&elf, ldpath))) {
87             goto done;
88         }
89
90         // Is this the valid loader?
91         if (!elf32_static_linked(&elf) || !elf32_check_exec(&elf)) {
92             errno = ELIBBAD;
93             goto done_close_elf32;
94         }
95
96         // TODO: relocate loader
97     } else {
98         context->entry = elf.eheader.e_entry;
99     }
100
101     struct v_file* elfile = (struct v_file*)elf.elf_file;
102
103     for (size_t i = 0; i < elf.eheader.e_phnum && !errno; i++) {
104         struct elf32_phdr* phdr = &elf.pheaders[i];
105
106         if (phdr->p_type == PT_LOAD) {
107             if (phdr->p_align != PG_SIZE) {
108                 // surprising alignment!
109                 errno = ENOEXEC;
110                 continue;
111             }
112
113             errno = elf32_smap(context, &elf, phdr);
114         }
115         // TODO Handle relocation
116     }
117
118 done_close_elf32:
119     elf32_close(&elf);
120 done:
121     vfree_safe(ldpath);
122     return errno;
123 }