3fb671c69b405e9a0c025c4e7daa38c5ed2c0beb
[lunaix-os.git] / lunaix-os / kernel / exe / elf32 / elf32bfmt.c
1 #include <lunaix/exebi/elf32.h>
2 #include <lunaix/fs.h>
3 #include <lunaix/mm/valloc.h>
4 #include <lunaix/spike.h>
5
6 #include <klibc/string.h>
7
8 static inline int
9 elf32_read(struct v_file* elf, void* data, size_t off, size_t len)
10 {
11     // it is wise to do cached read
12     return pcache_read(elf->inode, data, len, off);
13 }
14
15 int
16 elf32_open(struct elf32* elf, const char* path)
17 {
18     struct v_dnode* elfdn;
19     struct v_file* elffile;
20     int error = 0;
21
22     if ((error = vfs_walk_proc(path, &elfdn, NULL, 0))) {
23         return error;
24     }
25
26     if ((error = vfs_open(elfdn, &elffile))) {
27         return error;
28     }
29
30     return elf32_openat(elf, elffile);
31 }
32
33 int
34 elf32_openat(struct elf32* elf, const void* elf_vfile)
35 {
36     int status = 0;
37     elf->pheaders = NULL;
38     elf->elf_file = elf_vfile;
39
40     if ((status = elf32_read_ehdr(elf)) < 0) {
41         elf32_close(elf);
42         return status;
43     }
44
45     if ((status = elf32_read_phdr(elf)) < 0) {
46         elf32_close(elf);
47         return status;
48     }
49
50     return 0;
51 }
52
53 int
54 elf32_close(struct elf32* elf)
55 {
56     if (elf->pheaders) {
57         vfree(elf->pheaders);
58     }
59
60     if (elf->elf_file) {
61         vfs_close((struct v_file*)elf->elf_file);
62     }
63
64     memset(elf, 0, sizeof(*elf));
65
66     return 0;
67 }
68
69 int
70 elf32_static_linked(const struct elf32* elf)
71 {
72     for (size_t i = 0; i < elf->eheader.e_phnum; i++) {
73         struct elf32_phdr* phdre = &elf->pheaders[i];
74         if (phdre->p_type == PT_INTERP) {
75             return 0;
76         }
77     }
78     return 1;
79 }
80
81 size_t
82 elf32_loadable_memsz(const struct elf32* elf)
83 {
84     // XXX: Hmmmm, I am not sure if we need this. This is designed to be handy
85     // if we decided to map the heap region before transfer to loader. As
86     // currently, we push *everything* to user-space loader, thus we modify the
87     // brk syscall to do the initial heap mapping.
88
89     size_t sz = 0;
90     for (size_t i = 0; i < elf->eheader.e_phnum; i++) {
91         struct elf32_phdr* phdre = &elf->pheaders[i];
92         if (phdre->p_type == PT_LOAD) {
93             sz += phdre->p_memsz;
94         }
95     }
96
97     return sz;
98 }
99
100 int
101 elf32_find_loader(const struct elf32* elf, char* path_out, size_t len)
102 {
103     int retval = NO_LOADER;
104
105     assert_msg(len >= sizeof(DEFAULT_LOADER), "path_out: too small");
106
107     struct v_file* elfile = (struct v_file*)elf->elf_file;
108
109     for (size_t i = 0; i < elf->eheader.e_phnum; i++) {
110         struct elf32_phdr* phdre = &elf->pheaders[i];
111         if (phdre->p_type == PT_INTERP) {
112             if (len >= phdre->p_filesz) {
113                 return EINVAL;
114             }
115
116             retval =
117               elf32_read(elfile, path_out, phdre->p_offset, phdre->p_filesz);
118
119             if (retval < 0) {
120                 return retval;
121             }
122
123             break;
124         }
125     }
126
127     return retval;
128 }
129
130 int
131 elf32_read_ehdr(struct elf32* elf)
132 {
133     struct v_file* elfile = (struct v_file*)elf->elf_file;
134
135     return elf32_read(elfile, (void*)&elf->eheader, 0, SIZE_EHDR);
136 }
137
138 int
139 elf32_read_phdr(struct elf32* elf)
140 {
141     int status = 0;
142
143     struct v_file* elfile = (struct v_file*)elf->elf_file;
144
145     size_t entries = elf->eheader.e_phnum;
146     size_t tbl_sz = entries * SIZE_PHDR;
147
148     struct elf32_phdr* phdrs = valloc(tbl_sz);
149
150     if (!phdrs) {
151         return ENOMEM;
152     }
153
154     status = elf32_read(elfile, phdrs, elf->eheader.e_phoff, tbl_sz);
155
156     if (status < 0) {
157         vfree(phdrs);
158         return status;
159     }
160
161     elf->pheaders = phdrs;
162     return entries;
163 }
164
165 int
166 elf32_check_exec(const struct elf32* elf, int type)
167 {
168     const struct elf32_ehdr* ehdr = &elf->eheader;
169
170     return (ehdr->e_entry) && ehdr->e_type == type;
171 }
172
173 int
174 elf32_check_arch(const struct elf32* elf)
175 {
176     const struct elf32_ehdr* ehdr = &elf->eheader;
177
178     return *(u32_t*)(ehdr->e_ident) == ELFMAGIC &&
179            ehdr->e_ident[EI_CLASS] == ELFCLASS32 &&
180            ehdr->e_ident[EI_DATA] == ELFDATA2LSB && ehdr->e_machine == EM_386;
181 }