scoutos / prex-0.9.0 / usr / server / exec / exec_elf.c @ 03e9c04a
History | View | Annotate | Download (8.96 KB)
1 |
/*
|
---|---|
2 |
* Copyright (c) 2005-2006, Kohsuke Ohtani
|
3 |
* All rights reserved.
|
4 |
*
|
5 |
* Redistribution and use in source and binary forms, with or without
|
6 |
* modification, are permitted provided that the following conditions
|
7 |
* are met:
|
8 |
* 1. Redistributions of source code must retain the above copyright
|
9 |
* notice, this list of conditions and the following disclaimer.
|
10 |
* 2. Redistributions in binary form must reproduce the above copyright
|
11 |
* notice, this list of conditions and the following disclaimer in the
|
12 |
* documentation and/or other materials provided with the distribution.
|
13 |
* 3. Neither the name of the author nor the names of any co-contributors
|
14 |
* may be used to endorse or promote products derived from this software
|
15 |
* without specific prior written permission.
|
16 |
*
|
17 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
18 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
19 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
20 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
21 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
22 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
23 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
24 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
25 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
26 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
27 |
* SUCH DAMAGE.
|
28 |
*/
|
29 |
|
30 |
/*
|
31 |
* exec_elf.c - ELF file loader
|
32 |
*/
|
33 |
|
34 |
#include <sys/prex.h> |
35 |
#include <ipc/fs.h> |
36 |
#include <ipc/proc.h> |
37 |
#include <sys/elf.h> |
38 |
#include <sys/param.h> |
39 |
|
40 |
#include <string.h> |
41 |
#include <limits.h> |
42 |
#include <stdio.h> |
43 |
#include <stdlib.h> |
44 |
#include <errno.h> |
45 |
|
46 |
#include "exec.h" |
47 |
|
48 |
#define SHF_VALID (SHF_ALLOC | SHF_EXECINSTR | SHF_ALLOC | SHF_WRITE)
|
49 |
|
50 |
#ifndef CONFIG_MMU
|
51 |
static char *sect_addr[32]; /* Array of section address */ |
52 |
#endif
|
53 |
|
54 |
#ifdef CONFIG_MMU
|
55 |
/*
|
56 |
* Load executable ELF file
|
57 |
*/
|
58 |
static int |
59 |
load_exec(Elf32_Ehdr *ehdr, task_t task, int fd, vaddr_t *entry)
|
60 |
{ |
61 |
Elf32_Phdr *phdr; |
62 |
void *addr, *mapped;
|
63 |
size_t size = 0;
|
64 |
int i;
|
65 |
|
66 |
phdr = (Elf32_Phdr *)((u_long)ehdr + ehdr->e_phoff); |
67 |
if (phdr == NULL) |
68 |
return ENOEXEC;
|
69 |
|
70 |
for (i = 0; i < (int)ehdr->e_phnum; i++, phdr++) { |
71 |
if (phdr->p_type != PT_LOAD)
|
72 |
continue;
|
73 |
|
74 |
addr = (void *)phdr->p_vaddr;
|
75 |
size = phdr->p_memsz; |
76 |
if (size == 0) |
77 |
continue;
|
78 |
|
79 |
if (vm_allocate(task, &addr, size, 0) != 0) |
80 |
return ENOMEM;
|
81 |
|
82 |
if (vm_map(task, (void *)phdr->p_vaddr, size, &mapped) != 0) |
83 |
return ENOEXEC;
|
84 |
if (phdr->p_filesz > 0) { |
85 |
if (lseek(fd, (off_t)phdr->p_offset, SEEK_SET)
|
86 |
== -(off_t)1)
|
87 |
goto err;
|
88 |
if (read(fd, mapped, phdr->p_filesz) < 0) |
89 |
goto err;
|
90 |
} |
91 |
|
92 |
vm_free(task_self(), mapped); |
93 |
|
94 |
/* Set read-only to text */
|
95 |
if (phdr->p_flags & PF_X) {
|
96 |
if (vm_attribute(task, addr, PROT_READ) != 0) |
97 |
return ENOEXEC;
|
98 |
} |
99 |
} |
100 |
*entry = (vaddr_t)ehdr->e_entry; |
101 |
return 0; |
102 |
|
103 |
err:
|
104 |
vm_free(task_self(), mapped); |
105 |
return EIO;
|
106 |
} |
107 |
#else /* !CONFIG_MMU */ |
108 |
|
109 |
static int |
110 |
relocate_section_rela(Elf32_Sym *sym_table, Elf32_Rela *rela, |
111 |
char *target_sect, int nr_reloc) |
112 |
{ |
113 |
Elf32_Sym *sym; |
114 |
Elf32_Addr sym_val; |
115 |
int i;
|
116 |
|
117 |
for (i = 0; i < nr_reloc; i++) { |
118 |
sym = &sym_table[ELF32_R_SYM(rela->r_info)]; |
119 |
if (sym->st_shndx != STN_UNDEF) {
|
120 |
sym_val = (Elf32_Addr)sect_addr[sym->st_shndx] |
121 |
+ sym->st_value; |
122 |
if (relocate_rela(rela, sym_val, target_sect) != 0) |
123 |
return -1; |
124 |
} else if (ELF32_ST_BIND(sym->st_info) == STB_WEAK) { |
125 |
DPRINTF(("undefined weak symbol for rela[%d]\n", i));
|
126 |
} |
127 |
rela++; |
128 |
} |
129 |
return 0; |
130 |
} |
131 |
|
132 |
static int |
133 |
relocate_section_rel(Elf32_Sym *sym_table, Elf32_Rel *rel, |
134 |
char *target_sect, int nr_reloc) |
135 |
{ |
136 |
Elf32_Sym *sym; |
137 |
Elf32_Addr sym_val; |
138 |
int i;
|
139 |
|
140 |
for (i = 0; i < nr_reloc; i++) { |
141 |
sym = &sym_table[ELF32_R_SYM(rel->r_info)]; |
142 |
if (sym->st_shndx != STN_UNDEF) {
|
143 |
sym_val = (Elf32_Addr)sect_addr[sym->st_shndx] |
144 |
+ sym->st_value; |
145 |
if (relocate_rel(rel, sym_val, target_sect) != 0) |
146 |
return -1; |
147 |
} else if (ELF32_ST_BIND(sym->st_info) == STB_WEAK) { |
148 |
DPRINTF(("undefined weak symbol for rel[%d]\n", i));
|
149 |
} |
150 |
rel++; |
151 |
} |
152 |
return 0; |
153 |
} |
154 |
|
155 |
/*
|
156 |
* Relocate ELF sections
|
157 |
*/
|
158 |
static int |
159 |
relocate_section(Elf32_Shdr *shdr, char *rel_data)
|
160 |
{ |
161 |
Elf32_Sym *sym_table; |
162 |
char *target_sect;
|
163 |
int nr_reloc, error;
|
164 |
|
165 |
if (shdr->sh_entsize == 0) |
166 |
return 0; |
167 |
if ((target_sect = sect_addr[shdr->sh_info]) == 0) |
168 |
return -1; |
169 |
if ((sym_table = (Elf32_Sym *)sect_addr[shdr->sh_link]) == 0) |
170 |
return -1; |
171 |
|
172 |
nr_reloc = (int)(shdr->sh_size / shdr->sh_entsize);
|
173 |
switch (shdr->sh_type) {
|
174 |
case SHT_REL:
|
175 |
error = relocate_section_rel(sym_table, (Elf32_Rel *)rel_data, |
176 |
target_sect, nr_reloc); |
177 |
break;
|
178 |
|
179 |
case SHT_RELA:
|
180 |
error = relocate_section_rela(sym_table, (Elf32_Rela *)rel_data, |
181 |
target_sect, nr_reloc); |
182 |
break;
|
183 |
|
184 |
default:
|
185 |
error = -1;
|
186 |
break;
|
187 |
} |
188 |
return error;
|
189 |
} |
190 |
|
191 |
/*
|
192 |
* Load ELF relocatable file.
|
193 |
*/
|
194 |
static int |
195 |
load_reloc(Elf32_Ehdr *ehdr, task_t task, int fd, vaddr_t *entry)
|
196 |
{ |
197 |
Elf32_Shdr *shdr; |
198 |
char *buf;
|
199 |
void *base, *addr, *mapped;
|
200 |
size_t shdr_size, total_size; |
201 |
int i, error = 0; |
202 |
|
203 |
DPRINTF(("exec: load_reloc\n"));
|
204 |
|
205 |
/* Read section header */
|
206 |
shdr_size = ehdr->e_shentsize * ehdr->e_shnum; |
207 |
if ((buf = malloc(shdr_size)) == NULL) { |
208 |
error = ENOMEM; |
209 |
goto out0;
|
210 |
} |
211 |
|
212 |
if (lseek(fd, ehdr->e_shoff, SEEK_SET) < 0) { |
213 |
error = EIO; |
214 |
goto out1;
|
215 |
} |
216 |
if (read(fd, buf, shdr_size) < 0) { |
217 |
error = EIO; |
218 |
goto out1;
|
219 |
} |
220 |
|
221 |
/* Allocate memory for text, data and bss. */
|
222 |
shdr = (Elf32_Shdr *)buf; |
223 |
total_size = 0;
|
224 |
for (i = 0; i < ehdr->e_shnum; i++, shdr++) { |
225 |
if (shdr->sh_type == SHT_NOBITS) { /* bss? */ |
226 |
total_size = shdr->sh_addr + shdr->sh_size; |
227 |
break;
|
228 |
} |
229 |
} |
230 |
if (total_size == 0) { |
231 |
error = ENOEXEC; |
232 |
goto out1;
|
233 |
} |
234 |
if (vm_allocate(task, &base, total_size, 1) != 0) { |
235 |
DPRINTF(("exec: out of text\n"));
|
236 |
error = ENOMEM; |
237 |
goto out1;
|
238 |
} |
239 |
|
240 |
if (vm_map(task, base, total_size, &mapped) != 0) { |
241 |
error = ENOMEM; |
242 |
goto out1;
|
243 |
} |
244 |
|
245 |
/* Copy sections */
|
246 |
shdr = (Elf32_Shdr *)buf; |
247 |
for (i = 0; i < ehdr->e_shnum; i++, shdr++) { |
248 |
/*
|
249 |
*DPRINTF(("section: type=%x addr=%x size=%d offset=%x flags=%x\n",
|
250 |
* shdr->sh_type, shdr->sh_addr, shdr->sh_size,
|
251 |
* shdr->sh_offset, shdr->sh_flags));
|
252 |
*/
|
253 |
sect_addr[i] = 0;
|
254 |
if (shdr->sh_type == SHT_PROGBITS) {
|
255 |
switch (shdr->sh_flags & SHF_VALID) {
|
256 |
case (SHF_ALLOC | SHF_EXECINSTR): /* text */ |
257 |
case (SHF_ALLOC | SHF_WRITE): /* data */ |
258 |
case SHF_ALLOC: /* rodata */ |
259 |
break;
|
260 |
default:
|
261 |
continue;
|
262 |
} |
263 |
addr = (char *)((u_long)mapped + shdr->sh_addr);
|
264 |
if (shdr->sh_size == 0) { |
265 |
continue;
|
266 |
} |
267 |
} else if (shdr->sh_type == SHT_NOBITS) { |
268 |
/* bss */
|
269 |
sect_addr[i] = \ |
270 |
(char *)((u_long)mapped + shdr->sh_addr);
|
271 |
continue;
|
272 |
} else if (shdr->sh_type == SHT_SYMTAB || |
273 |
shdr->sh_type == SHT_RELA || |
274 |
shdr->sh_type == SHT_REL) |
275 |
{ |
276 |
|
277 |
if ((addr = malloc(shdr->sh_size)) == NULL) { |
278 |
error = ENOMEM; |
279 |
goto out2;
|
280 |
} |
281 |
} else
|
282 |
continue;
|
283 |
|
284 |
if (lseek(fd, shdr->sh_offset, SEEK_SET) < 0) { |
285 |
error = EIO; |
286 |
goto out2;
|
287 |
} |
288 |
if (read(fd, addr, shdr->sh_size) < 0) { |
289 |
error = EIO; |
290 |
goto out2;
|
291 |
} |
292 |
sect_addr[i] = addr; |
293 |
} |
294 |
|
295 |
/* Process relocation */
|
296 |
shdr = (Elf32_Shdr *)buf; |
297 |
for (i = 0; i < ehdr->e_shnum; i++, shdr++) { |
298 |
if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) {
|
299 |
if (relocate_section(shdr, sect_addr[i]) != 0) { |
300 |
error = EIO; |
301 |
DPRINTF(("exec: relocation failed\n"));
|
302 |
goto out2;
|
303 |
} |
304 |
} |
305 |
} |
306 |
*entry = (vaddr_t)((u_long)mapped + ehdr->e_entry); |
307 |
DPRINTF(("exec: entry=%x\n", *entry));
|
308 |
out2:
|
309 |
/* Release symbol table */
|
310 |
shdr = (Elf32_Shdr *)buf; |
311 |
for (i = 0; i < ehdr->e_shnum; i++, shdr++) { |
312 |
if (shdr->sh_type == SHT_SYMTAB ||
|
313 |
shdr->sh_type == SHT_RELA || |
314 |
shdr->sh_type == SHT_REL) { |
315 |
if (sect_addr[i])
|
316 |
free(sect_addr[i]); |
317 |
} |
318 |
} |
319 |
vm_free(task_self(), mapped); |
320 |
out1:
|
321 |
free(buf); |
322 |
out0:
|
323 |
DPRINTF(("exec: load_reloc ret=%d\n", error));
|
324 |
return error;
|
325 |
} |
326 |
|
327 |
#endif /* !CONFIG_MMU */ |
328 |
|
329 |
|
330 |
/*
|
331 |
* Load ELF file
|
332 |
*/
|
333 |
int
|
334 |
elf_load(struct exec *exec)
|
335 |
{ |
336 |
int error, fd;
|
337 |
|
338 |
/*
|
339 |
* Check permission.
|
340 |
*/
|
341 |
if (access(exec->path, X_OK) == -1) { |
342 |
DPRINTF(("exec: no exec access\n"));
|
343 |
return errno;
|
344 |
} |
345 |
|
346 |
if ((fd = open(exec->path, O_RDONLY)) == -1) |
347 |
return ENOENT;
|
348 |
|
349 |
#ifdef CONFIG_MMU
|
350 |
error = load_exec((Elf32_Ehdr *)exec->header, exec->task, |
351 |
fd, &exec->entry); |
352 |
#else
|
353 |
error = load_reloc((Elf32_Ehdr *)exec->header, exec->task, |
354 |
fd, &exec->entry); |
355 |
#endif
|
356 |
close(fd); |
357 |
return error;
|
358 |
} |
359 |
|
360 |
/*
|
361 |
* Probe ELF file
|
362 |
*/
|
363 |
int
|
364 |
elf_probe(struct exec *exec)
|
365 |
{ |
366 |
Elf32_Ehdr *ehdr; |
367 |
|
368 |
/* Check ELF header */
|
369 |
ehdr = (Elf32_Ehdr *)exec->header; |
370 |
DPRINTF(("exec: ELF magic %c %c %c %c\n",
|
371 |
ehdr->e_ident[EI_MAG0], |
372 |
ehdr->e_ident[EI_MAG1], |
373 |
ehdr->e_ident[EI_MAG2], |
374 |
ehdr->e_ident[EI_MAG3])); |
375 |
|
376 |
if ((ehdr->e_ident[EI_MAG0] != ELFMAG0) ||
|
377 |
(ehdr->e_ident[EI_MAG1] != ELFMAG1) || |
378 |
(ehdr->e_ident[EI_MAG2] != ELFMAG2) || |
379 |
(ehdr->e_ident[EI_MAG3] != ELFMAG3)) |
380 |
return PROBE_ERROR;
|
381 |
|
382 |
#ifdef CONFIG_MMU
|
383 |
if (ehdr->e_type != ET_EXEC)
|
384 |
return PROBE_ERROR;
|
385 |
#else
|
386 |
if (ehdr->e_type != ET_REL)
|
387 |
return PROBE_ERROR;
|
388 |
#endif
|
389 |
return PROBE_MATCH;
|
390 |
} |
391 |
|
392 |
void
|
393 |
elf_init(void)
|
394 |
{ |
395 |
} |