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