root/haiku/trunk/src/system/boot/loader/elf.cpp

Revision 27753, 11.8 KB (checked in by bonefish, 3 months ago)

Reverted r27685, r27676, r27665, and r27664, the changes related to
letting the boot loader provide full paths for the pre-loaded images.

  • Property svn:eol-style set to native
  • Property svn:keywords set to author date id revision
Line 
1/*
2 * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "elf.h"
8
9#include <boot/arch.h>
10#include <boot/platform.h>
11#include <boot/stage2.h>
12#include <elf32.h>
13#include <kernel.h>
14
15#include <unistd.h>
16#include <string.h>
17#include <stdlib.h>
18
19//#define TRACE_ELF
20#ifdef TRACE_ELF
21#       define TRACE(x) dprintf x
22#else
23#       define TRACE(x) ;
24#endif
25
26
27static status_t
28verify_elf_header(struct Elf32_Ehdr &header)
29{
30        if (memcmp(header.e_ident, ELF_MAGIC, 4) != 0
31                || header.e_ident[4] != ELFCLASS32
32                || header.e_phoff == 0
33                || !header.IsHostEndian()
34                || header.e_phentsize != sizeof(struct Elf32_Phdr))
35                return B_BAD_TYPE;
36
37        return B_OK;
38}
39
40
41static status_t
42elf_parse_dynamic_section(struct preloaded_image *image)
43{
44        image->syms = 0;
45        image->rel = 0;
46        image->rel_len = 0;
47        image->rela = 0;
48        image->rela_len = 0;
49        image->pltrel = 0;
50        image->pltrel_len = 0;
51        image->pltrel_type = 0;
52
53        struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_section.start;
54        if (!d)
55                return B_ERROR;
56
57        for (int i = 0; d[i].d_tag != DT_NULL; i++) {
58                switch (d[i].d_tag) {
59                        case DT_HASH:
60                        case DT_STRTAB:
61                                break;
62                        case DT_SYMTAB:
63                                image->syms = (struct Elf32_Sym *)(d[i].d_un.d_ptr
64                                        + image->text_region.delta);
65                                break;
66                        case DT_REL:
67                                image->rel = (struct Elf32_Rel *)(d[i].d_un.d_ptr
68                                        + image->text_region.delta);
69                                break;
70                        case DT_RELSZ:
71                                image->rel_len = d[i].d_un.d_val;
72                                break;
73                        case DT_RELA:
74                                image->rela = (struct Elf32_Rela *)(d[i].d_un.d_ptr
75                                        + image->text_region.delta);
76                                break;
77                        case DT_RELASZ:
78                                image->rela_len = d[i].d_un.d_val;
79                                break;
80                        case DT_JMPREL:
81                                image->pltrel = (struct Elf32_Rel *)(d[i].d_un.d_ptr
82                                        + image->text_region.delta);
83                                break;
84                        case DT_PLTRELSZ:
85                                image->pltrel_len = d[i].d_un.d_val;
86                                break;
87                        case DT_PLTREL:
88                                image->pltrel_type = d[i].d_un.d_val;
89                                break;
90
91                        default:
92                                continue;
93                }
94        }
95
96        // lets make sure we found all the required sections
97        if (image->syms == NULL)
98                return B_ERROR;
99
100        return B_OK;
101}
102
103
104static status_t
105load_elf_symbol_table(int fd, preloaded_image *image)
106{
107        struct Elf32_Ehdr &elfHeader = image->elf_header;
108        Elf32_Sym *symbolTable = NULL;
109        Elf32_Shdr *stringHeader = NULL;
110        uint32 numSymbols = 0;
111        char *stringTable;
112        status_t status;
113
114        // get section headers
115
116        ssize_t size = elfHeader.e_shnum * elfHeader.e_shentsize;
117        Elf32_Shdr *sectionHeaders = (struct Elf32_Shdr *)malloc(size);
118        if (sectionHeaders == NULL) {
119                dprintf("error allocating space for section headers\n");
120                return B_NO_MEMORY;
121        }
122
123        ssize_t length = read_pos(fd, elfHeader.e_shoff, sectionHeaders, size);
124        if (length < size) {
125                TRACE(("error reading in program headers\n"));
126                status = B_ERROR;
127                goto error1;
128        }
129       
130        // find symbol table in section headers
131       
132        for (int32 i = 0; i < elfHeader.e_shnum; i++) {
133                if (sectionHeaders[i].sh_type == SHT_SYMTAB) {
134                        stringHeader = &sectionHeaders[sectionHeaders[i].sh_link];
135
136                        if (stringHeader->sh_type != SHT_STRTAB) {
137                                TRACE(("doesn't link to string table\n"));
138                                status = B_BAD_DATA;
139                                goto error1;
140                        }
141
142                        // read in symbol table
143                        symbolTable = (Elf32_Sym *)kernel_args_malloc(
144                                size = sectionHeaders[i].sh_size);
145                        if (symbolTable == NULL) {
146                                status = B_NO_MEMORY;
147                                goto error1;
148                        }
149
150                        length = read_pos(fd, sectionHeaders[i].sh_offset, symbolTable,
151                                size);
152                        if (length < size) {
153                                TRACE(("error reading in symbol table\n"));
154                                status = B_ERROR;
155                                goto error1;
156                        }
157
158                        numSymbols = size / sizeof(Elf32_Sym);
159                        break;
160                }
161        }
162
163        if (symbolTable == NULL) {
164                TRACE(("no symbol table\n"));
165                status = B_BAD_VALUE;
166                goto error1;
167        }
168
169        // read in string table
170
171        stringTable = (char *)kernel_args_malloc(size = stringHeader->sh_size);
172        if (stringTable == NULL) {
173                status = B_NO_MEMORY;
174                goto error2;
175        }
176
177        length = read_pos(fd, stringHeader->sh_offset, stringTable, size);
178        if (length < size) {
179                TRACE(("error reading in string table\n"));
180                status = B_ERROR;
181                goto error3;
182        }
183
184        TRACE(("loaded %ld debug symbols\n", numSymbols));
185
186        // insert tables into image
187        image->debug_symbols = symbolTable;
188        image->num_debug_symbols = numSymbols;
189        image->debug_string_table = stringTable;
190        image->debug_string_table_size = size;
191
192        free(sectionHeaders);
193        return B_OK;
194
195error3:
196        kernel_args_free(stringTable);
197error2:
198        kernel_args_free(symbolTable);
199error1:
200        free(sectionHeaders);
201
202        return status;
203}
204
205
206status_t
207elf_load_image(int fd, preloaded_image *image)
208{
209        size_t totalSize;
210        status_t status;
211
212        TRACE(("elf_load_image(fd = %d, image = %p)\n", fd, image));
213
214        struct Elf32_Ehdr &elfHeader = image->elf_header;
215
216        ssize_t length = read_pos(fd, 0, &elfHeader, sizeof(Elf32_Ehdr));
217        if (length < (ssize_t)sizeof(Elf32_Ehdr))
218                return B_BAD_TYPE;
219
220        status = verify_elf_header(elfHeader);
221        if (status < B_OK)
222                return status;
223
224        ssize_t size = elfHeader.e_phnum * elfHeader.e_phentsize;
225        Elf32_Phdr *programHeaders = (struct Elf32_Phdr *)malloc(size);
226        if (programHeaders == NULL) {
227                dprintf("error allocating space for program headers\n");
228                return B_NO_MEMORY;
229        }
230
231        length = read_pos(fd, elfHeader.e_phoff, programHeaders, size);
232        if (length < size) {
233                TRACE(("error reading in program headers\n"));
234                status = B_ERROR;
235                goto error1;
236        }
237
238        // create an area large enough to hold the image
239
240        image->data_region.size = 0;
241        image->text_region.size = 0;
242
243        for (int32 i = 0; i < elfHeader.e_phnum; i++) {
244                Elf32_Phdr &header = programHeaders[i];
245
246                switch (header.p_type) {
247                        case PT_LOAD:
248                                break;
249                        case PT_DYNAMIC:
250                                image->dynamic_section.start = header.p_vaddr;
251                                image->dynamic_section.size = header.p_memsz;
252                                continue;
253                        case PT_INTERP:
254                        case PT_PHDR:
255                                // known but unused type
256                                continue;
257                        default:
258                                dprintf("unhandled pheader type 0x%lx\n", header.p_type);
259                                continue;
260                }
261
262                elf_region *region;
263                if (header.IsReadWrite()) {
264                        if (image->data_region.size != 0) {
265                                dprintf("elf: rw already handled!\n");
266                                continue;
267                        }
268                        region = &image->data_region;
269                } else if (header.IsExecutable()) {
270                        if (image->text_region.size != 0) {
271                                dprintf("elf: ro already handled!\n");
272                                continue;
273                        }
274                        region = &image->text_region;
275                } else
276                        continue;
277
278                region->start = ROUNDOWN(header.p_vaddr, B_PAGE_SIZE);
279                region->size = ROUNDUP(header.p_memsz + (header.p_vaddr % B_PAGE_SIZE),
280                        B_PAGE_SIZE);
281                region->delta = -region->start;
282
283                TRACE(("segment %d: start = %p, size = %lu, delta = %lx\n", i,
284                        region->start, region->size, region->delta));
285        }
286
287        // found both, text and data?
288        if (image->data_region.size == 0 || image->text_region.size == 0) {
289                dprintf("Couldn't find both text and data segment!\n");
290                status = B_BAD_DATA;
291                goto error1;
292        }
293
294        // get the segment order
295        elf_region *firstRegion;
296        elf_region *secondRegion;
297        if (image->text_region.start < image->data_region.start) {
298                firstRegion = &image->text_region;
299                secondRegion = &image->data_region;
300        } else {
301                firstRegion = &image->data_region;
302                secondRegion = &image->text_region;
303        }
304
305        // Check whether the segments have an unreasonable amount of unused space
306        // inbetween.
307        totalSize = secondRegion->start + secondRegion->size - firstRegion->start;
308        if (totalSize > image->text_region.size + image->data_region.size
309                + 8 * 1024) {
310                status = B_BAD_DATA;
311                goto error1;
312        }
313
314        // The kernel and the modules are relocatable, thus
315        // platform_allocate_region() can automatically allocate an address,
316        // but shall prefer the specified base address.
317        if (platform_allocate_region((void **)&firstRegion->start, totalSize,
318                        B_READ_AREA | B_WRITE_AREA, false) < B_OK) {
319                status = B_NO_MEMORY;
320                goto error1;
321        }
322
323        // initialize the region pointers to the allocated region
324        secondRegion->start += firstRegion->start + firstRegion->delta;
325
326        image->data_region.delta += image->data_region.start;
327        image->text_region.delta += image->text_region.start;
328
329        // load program data
330
331        for (int i = 0; i < elfHeader.e_phnum; i++) {
332                Elf32_Phdr &header = programHeaders[i];
333
334                if (header.p_type != PT_LOAD)
335                        continue;
336
337                elf_region *region;
338                if (header.IsReadWrite())
339                        region = &image->data_region;
340                else if (header.IsExecutable())
341                        region = &image->text_region;
342                else
343                        continue;
344
345                TRACE(("load segment %d (%ld bytes)...\n", i, header.p_filesz));
346
347                length = read_pos(fd, header.p_offset,
348                        (void *)(region->start + (header.p_vaddr % B_PAGE_SIZE)),
349                        header.p_filesz);
350                if (length < (ssize_t)header.p_filesz) {
351                        status = B_BAD_DATA;
352                        dprintf("error reading in seg %d\n", i);
353                        goto error2;
354                }
355
356                // Clear anything above the file size (that may also contain the BSS
357                // area)
358
359                uint32 offset = (header.p_vaddr % B_PAGE_SIZE) + header.p_filesz;
360                if (offset < region->size)
361                        memset((void *)(region->start + offset), 0, region->size - offset);
362        }
363
364        // offset dynamic section, and program entry addresses by the delta of the
365        // regions
366        image->dynamic_section.start += image->text_region.delta;
367        image->elf_header.e_entry += image->text_region.delta;
368
369        image->num_debug_symbols = 0;
370        image->debug_symbols = NULL;
371        image->debug_string_table = NULL;
372
373        // ToDo: this should be enabled by kernel settings!
374        if (1)
375                load_elf_symbol_table(fd, image);
376
377        free(programHeaders);
378
379        return B_OK;
380
381error2:
382        if (image->text_region.start != 0)
383                platform_free_region((void *)image->text_region.start, totalSize);
384error1:
385        free(programHeaders);
386
387        return status;
388}
389
390
391status_t
392elf_load_image(Directory *directory, const char *path)
393{
394        preloaded_image *image;
395
396        TRACE(("elf_load_image(directory = %p, \"%s\")\n", directory, path));
397
398        int fd = open_from(directory, path, O_RDONLY);
399        if (fd < 0)
400                return fd;
401
402        // check if this file has already been loaded
403
404        struct stat stat;
405        fstat(fd, &stat);
406
407        image = gKernelArgs.preloaded_images;
408        for (; image != NULL; image = image->next) {
409                if (image->inode == stat.st_ino) {
410                        // file has already been loaded, no need to load it twice!
411                        close(fd);
412                        return B_OK;
413                }
414        }
415
416        // we still need to load it, so do it
417
418        image = (preloaded_image *)kernel_args_malloc(sizeof(preloaded_image));
419        if (image == NULL) {
420                close(fd);
421                return B_NO_MEMORY;
422        }
423
424        status_t status = elf_load_image(fd, image);
425        if (status == B_OK) {
426                image->name = kernel_args_strdup(path);
427                image->inode = stat.st_ino;
428
429                // insert to kernel args
430                image->next = gKernelArgs.preloaded_images;
431                gKernelArgs.preloaded_images = image;
432        } else
433                kernel_args_free(image);
434
435        close(fd);
436        return status;
437}
438
439
440status_t
441elf_relocate_image(struct preloaded_image *image)
442{
443        status_t status = elf_parse_dynamic_section(image);
444        if (status != B_OK)
445                return status;
446
447        // deal with the rels first
448        if (image->rel) {
449                TRACE(("total %i relocs\n",
450                        image->rel_len / (int)sizeof(struct Elf32_Rel)));
451
452                status = boot_arch_elf_relocate_rel(image, image->rel, image->rel_len);
453                if (status < B_OK)
454                        return status;
455        }
456
457        if (image->pltrel) {
458                TRACE(("total %i plt-relocs\n",
459                        image->pltrel_len / (int)sizeof(struct Elf32_Rel)));
460
461                if (image->pltrel_type == DT_REL) {
462                        status = boot_arch_elf_relocate_rel(image, image->pltrel,
463                                image->pltrel_len);
464                } else {
465                        status = boot_arch_elf_relocate_rela(image,
466                                (struct Elf32_Rela *)image->pltrel, image->pltrel_len);
467                }
468                if (status < B_OK)
469                        return status;
470        }
471
472        if (image->rela) {
473                TRACE(("total %i rela relocs\n",
474                        image->rela_len / (int)sizeof(struct Elf32_Rela)));
475                status = boot_arch_elf_relocate_rela(image, image->rela,
476                        image->rela_len);
477                if (status < B_OK)
478                        return status;
479        }
480
481        return B_OK;
482}
483
484
485status_t
486boot_elf_resolve_symbol(struct preloaded_image *image,
487        struct Elf32_Sym *symbol, addr_t *symbolAddress)
488{
489        switch (symbol->st_shndx) {
490                case SHN_UNDEF:
491                        // Since we do that only for the kernel, there shouldn't be
492                        // undefined symbols.
493                        return B_MISSING_SYMBOL;
494                case SHN_ABS:
495                        *symbolAddress = symbol->st_value;
496                        return B_NO_ERROR;
497                case SHN_COMMON:
498                        // ToDo: finish this
499                        TRACE(("elf_resolve_symbol: COMMON symbol, finish me!\n"));
500                        return B_ERROR;
501                default:
502                        // standard symbol
503                        *symbolAddress = symbol->st_value + image->text_region.delta;
504                        return B_NO_ERROR;
505        }
506}
Note: See TracBrowser for help on using the browser.