Statistics
| Branch: | Revision:

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
}