source: bootcd/isolinux/syslinux-6.03/com32/lib/sys/module/i386/elf_module.c

Last change on this file was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 7.8 KB
Line 
1/*
2 * elf_module.c
3 *
4 *  Created on: Aug 11, 2008
5 *      Author: Stefan Bucur <stefanb@zytor.com>
6 */
7
8#include <errno.h>
9#include <stdlib.h>
10#include <string.h>
11#include <stdio.h>
12#include <elf.h>
13#include <dprintf.h>
14#include <core.h>
15
16#include <linux/list.h>
17#include <sys/module.h>
18#include <sys/exec.h>
19
20#include "elfutils.h"
21#include "../common.h"
22
23/*
24 *
25 * The implementation assumes that the loadable segments are present
26 * in the PHT sorted by their offsets, so that only forward seeks would
27 * be necessary.
28 */
29int load_segments(struct elf_module *module, Elf_Ehdr *elf_hdr) {
30        int i;
31        int res = 0;
32        char *pht = NULL;
33        char *sht = NULL;
34        Elf32_Phdr *cr_pht;
35        Elf32_Shdr *cr_sht;
36
37        Elf32_Addr min_addr  = 0x00000000; // Min. ELF vaddr
38        Elf32_Addr max_addr  = 0x00000000; // Max. ELF vaddr
39        Elf32_Word max_align = sizeof(void*); // Min. align of posix_memalign()
40        Elf32_Addr min_alloc, max_alloc;   // Min. and max. aligned allocables
41
42        Elf32_Addr dyn_addr = 0x00000000;
43
44        // Get to the PHT
45        image_seek(elf_hdr->e_phoff, module);
46
47        // Load the PHT
48        pht = malloc(elf_hdr->e_phnum * elf_hdr->e_phentsize);
49        if (!pht)
50                return -1;
51
52        image_read(pht, elf_hdr->e_phnum * elf_hdr->e_phentsize, module);
53
54        // Compute the memory needings of the module
55        for (i=0; i < elf_hdr->e_phnum; i++) {
56                cr_pht = (Elf32_Phdr*)(pht + i * elf_hdr->e_phentsize);
57
58                switch (cr_pht->p_type) {
59                case PT_LOAD:
60                        if (i == 0) {
61                                min_addr = cr_pht->p_vaddr;
62                        } else {
63                                min_addr = MIN(min_addr, cr_pht->p_vaddr);
64                        }
65
66                        max_addr = MAX(max_addr, cr_pht->p_vaddr + cr_pht->p_memsz);
67                        max_align = MAX(max_align, cr_pht->p_align);
68                        break;
69                case PT_DYNAMIC:
70                        dyn_addr = cr_pht->p_vaddr;
71                        break;
72                default:
73                        // Unsupported - ignore
74                        break;
75                }
76        }
77
78        if (max_addr - min_addr == 0) {
79                // No loadable segments
80                DBG_PRINT("No loadable segments found\n");
81                goto out;
82        }
83
84        if (dyn_addr == 0) {
85                DBG_PRINT("No dynamic information segment found\n");
86                goto out;
87        }
88
89        // The minimum address that should be allocated
90        min_alloc = min_addr - (min_addr % max_align);
91
92        // The maximum address that should be allocated
93        max_alloc = max_addr - (max_addr % max_align);
94        if (max_addr % max_align > 0)
95                max_alloc += max_align;
96
97
98        if (elf_malloc(&module->module_addr,
99                        max_align,
100                        max_alloc-min_alloc) != 0) {
101
102                DBG_PRINT("Could not allocate segments\n");
103                goto out;
104        }
105
106        module->base_addr = (Elf32_Addr)(module->module_addr) - min_alloc;
107        module->module_size = max_alloc - min_alloc;
108
109        // Zero-initialize the memory
110        memset(module->module_addr, 0, module->module_size);
111
112        for (i = 0; i < elf_hdr->e_phnum; i++) {
113                cr_pht = (Elf32_Phdr*)(pht + i * elf_hdr->e_phentsize);
114
115                if (cr_pht->p_type == PT_LOAD) {
116                        // Copy the segment at its destination
117                        if (cr_pht->p_offset < module->u.l._cr_offset) {
118                                // The segment contains data before the current offset
119                                // It can be discarded without worry - it would contain only
120                                // headers
121                                Elf32_Off aux_off = module->u.l._cr_offset - cr_pht->p_offset;
122
123                                if (image_read((char *)module_get_absolute(cr_pht->p_vaddr, module) + aux_off,
124                                               cr_pht->p_filesz - aux_off, module) < 0) {
125                                        res = -1;
126                                        goto out;
127                                }
128                        } else {
129                                if (image_seek(cr_pht->p_offset, module) < 0) {
130                                        res = -1;
131                                        goto out;
132                                }
133
134                                if (image_read(module_get_absolute(cr_pht->p_vaddr, module),
135                                                cr_pht->p_filesz, module) < 0) {
136                                        res = -1;
137                                        goto out;
138                                }
139                        }
140
141                        /*
142                        DBG_PRINT("Loadable segment of size 0x%08x copied from vaddr 0x%08x at 0x%08x\n",
143                                        cr_pht->p_filesz,
144                                        cr_pht->p_vaddr,
145                                        (Elf32_Addr)module_get_absolute(cr_pht->p_vaddr, module));
146                        */
147                }
148        }
149
150        // Get to the SHT
151        image_seek(elf_hdr->e_shoff, module);
152
153        // Load the SHT
154        sht = malloc(elf_hdr->e_shnum * elf_hdr->e_shentsize);
155        if (!sht) {
156                res = -1;
157                goto out;
158        }
159
160        image_read(sht, elf_hdr->e_shnum * elf_hdr->e_shentsize, module);
161
162        // Setup the symtable size
163        for (i = 0; i < elf_hdr->e_shnum; i++) {
164                cr_sht = (Elf32_Shdr*)(sht + i * elf_hdr->e_shentsize);
165
166                if (cr_sht->sh_type == SHT_DYNSYM) {
167                        module->symtable_size = cr_sht->sh_size;
168                        break;
169                }
170        }
171
172        free(sht);
173
174        // Setup dynamic segment location
175        module->dyn_table = module_get_absolute(dyn_addr, module);
176
177        /*
178        DBG_PRINT("Base address: 0x%08x, aligned at 0x%08x\n", module->base_addr,
179                        max_align);
180        DBG_PRINT("Module size: 0x%08x\n", module->module_size);
181        */
182
183out:
184        // Free up allocated memory
185        if (pht != NULL)
186                free(pht);
187
188        return res;
189}
190
191int perform_relocation(struct elf_module *module, Elf_Rel *rel) {
192        Elf32_Word *dest = module_get_absolute(rel->r_offset, module);
193
194        // The symbol reference index
195        Elf32_Word sym = ELF32_R_SYM(rel->r_info);
196        unsigned char type = ELF32_R_TYPE(rel->r_info);
197
198        // The symbol definition (if applicable)
199        Elf32_Sym *sym_def = NULL;
200        struct elf_module *sym_module = NULL;
201        Elf32_Addr sym_addr = 0x0;
202
203        if (sym > 0) {
204                // Find out details about the symbol
205
206                // The symbol reference
207                Elf32_Sym *sym_ref = symbol_get_entry(module, sym);
208
209                // The symbol definition
210                sym_def =
211                        global_find_symbol(module->str_table + sym_ref->st_name,
212                                        &sym_module);
213
214                if (sym_def == NULL) {
215                        DBG_PRINT("Cannot perform relocation for symbol %s\n",
216                                        module->str_table + sym_ref->st_name);
217
218                        if (ELF32_ST_BIND(sym_ref->st_info) != STB_WEAK)
219                                return -1;
220
221                        // This must be a derivative-specific
222                        // function. We're OK as long as we never
223                        // execute the function.
224                        sym_def = global_find_symbol("undefined_symbol", &sym_module);
225                }
226
227                // Compute the absolute symbol virtual address
228                sym_addr = (Elf32_Addr)module_get_absolute(sym_def->st_value, sym_module);
229
230                if (sym_module != module) {
231                        // Create a dependency
232                        enforce_dependency(sym_module, module);
233                }
234        }
235
236        switch (type) {
237        case R_386_NONE:
238                // Do nothing
239                break;
240        case R_386_32:
241                *dest += sym_addr;
242                break;
243        case R_386_PC32:
244                *dest += sym_addr - (Elf32_Addr)dest;
245                break;
246        case R_386_COPY:
247                if (sym_addr > 0) {
248                        memcpy((void*)dest, (void*)sym_addr, sym_def->st_size);
249                }
250                break;
251        case R_386_GLOB_DAT:
252        case R_386_JMP_SLOT:
253                // Maybe TODO: Keep track of the GOT entries allocations
254                *dest = sym_addr;
255                break;
256        case R_386_RELATIVE:
257                *dest += module->base_addr;
258                break;
259        default:
260                DBG_PRINT("Relocation type %d not supported\n", type);
261                return -1;
262        }
263
264        return 0;
265}
266
267int resolve_symbols(struct elf_module *module) {
268        Elf32_Dyn  *dyn_entry = module->dyn_table;
269        unsigned int i;
270        int res;
271
272        Elf32_Word plt_rel_size = 0;
273        char *plt_rel = NULL;
274
275        char *rel = NULL;
276        Elf32_Word rel_size = 0;
277        Elf32_Word rel_entry = 0;
278
279        // The current relocation
280        Elf32_Rel *crt_rel;
281
282        while (dyn_entry->d_tag != DT_NULL) {
283                switch(dyn_entry->d_tag) {
284
285                // PLT relocation information
286                case DT_PLTRELSZ:
287                        plt_rel_size = dyn_entry->d_un.d_val;
288                        break;
289                case DT_PLTREL:
290                        if (dyn_entry->d_un.d_val != DT_REL) {
291                                DBG_PRINT("Unsupported PLT relocation\n");
292                                return -1;
293                        }
294                case DT_JMPREL:
295                        plt_rel = module_get_absolute(dyn_entry->d_un.d_ptr, module);
296                        break;
297
298                // Standard relocation information
299                case DT_REL:
300                        rel = module_get_absolute(dyn_entry->d_un.d_ptr, module);
301                        break;
302                case DT_RELSZ:
303                        rel_size = dyn_entry->d_un.d_val;
304                        break;
305                case DT_RELENT:
306                        rel_entry = dyn_entry->d_un.d_val;
307                        break;
308
309                // Module initialization and termination
310                case DT_INIT:
311                        // TODO Implement initialization functions
312                        break;
313                case DT_FINI:
314                        // TODO Implement finalization functions
315                        break;
316                }
317
318                dyn_entry++;
319        }
320
321        if (rel_size > 0) {
322                // Process standard relocations
323                for (i = 0; i < rel_size/rel_entry; i++) {
324                        crt_rel = (Elf32_Rel*)(rel + i*rel_entry);
325
326                        res = perform_relocation(module, crt_rel);
327
328                        if (res < 0)
329                                return res;
330                }
331
332        }
333
334        if (plt_rel_size > 0) {
335                // TODO: Permit this lazily
336                // Process PLT relocations
337                for (i = 0; i < plt_rel_size/sizeof(Elf32_Rel); i++) {
338                        crt_rel = (Elf32_Rel*)(plt_rel + i*sizeof(Elf32_Rel));
339
340                        res = perform_relocation(module, crt_rel);
341
342                        if (res < 0)
343                                return res;
344                }
345        }
346
347        return 0;
348}
349
Note: See TracBrowser for help on using the repository browser.