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