Small bits of sofware screen composition support.
[AROS.git] / bootstrap / elfloader.c
blobd269470ea1ce14539697da059de966e52f73dc79
1 /*
2 Copyright (C) 2006-2011 The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: ELF loader extracted from our internal_load_seg_elf in dos.library.
6 Lang: English
7 */
9 #include <inttypes.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
14 #include <dos/elf.h>
15 #include <libraries/debug.h>
17 #include <elfloader.h>
18 #include <runtime.h>
20 #define D(x)
21 #define DREL(x)
22 #define DSYM(x)
24 /* Use own definitions because we may be compiled as 32-bit code but build structures for 64-bit code */
25 struct ELF_ModuleInfo_t
27 elf_uintptr_t Next;
28 elf_uintptr_t Name;
29 unsigned short Type;
30 unsigned short Pad0; /* On i386 we have different alignment, so do explicit padding */
31 #ifdef ELF_64BIT
32 unsigned int Pad1;
33 #endif
34 elf_uintptr_t eh;
35 elf_uintptr_t sh;
38 /* Our own definition of struct KernelBSS, to avoid excessive castings */
39 struct KernelBSS_t
41 elf_uintptr_t addr;
42 elf_uintptr_t len;
45 static elf_uintptr_t SysBase_ptr = 0;
48 * Test for correct ELF header here
50 static char *check_header(struct elfheader *eh)
52 if (eh->ident[0] != 0x7f || eh->ident[1] != 'E' ||
53 eh->ident[2] != 'L' || eh->ident[3] != 'F')
54 return "Not a ELF file";
56 if (eh->type != ET_REL || eh->machine != AROS_ELF_MACHINE)
57 return "Wrong object type or wrong architecture";
59 /* No error */
60 return NULL;
64 * Get the memory for chunk and load it
66 static void *load_hunk(void *file, struct sheader *sh, void *addr, struct KernelBSS_t **bss_tracker)
68 unsigned long align;
70 /* empty chunk? Who cares :) */
71 if (!sh->size)
72 return addr;
74 D(kprintf("[ELF Loader] Chunk (%ld bytes, align=%ld (%p) @ ", sh->size, sh->addralign, (void *)sh->addralign));
75 align = sh->addralign - 1;
76 addr = (char *)(((unsigned long)addr + align) & ~align);
78 D(kprintf("%p\n", addr));
79 sh->addr = (elf_ptr_t)(unsigned long)addr;
81 /* copy block of memory from ELF file if it exists */
82 if (sh->type != SHT_NOBITS)
84 if (read_block(file, sh->offset, (void *)(unsigned long)sh->addr, sh->size))
85 return NULL;
87 else
89 memset(addr, 0, sh->size);
91 (*bss_tracker)->addr = (unsigned long)addr;
92 (*bss_tracker)->len = sh->size;
93 (*bss_tracker)++;
96 return addr + sh->size;
99 static void *copy_data(void *src, void *addr, unsigned long len)
101 memcpy(addr, src, len);
102 return addr + len;
105 /* Perform relocations of given section */
106 static int relocate(struct elfheader *eh, struct sheader *sh, long shrel_idx, elf_uintptr_t DefSysBase)
108 struct sheader *shrel = &sh[shrel_idx];
109 struct sheader *shsymtab = &sh[SHINDEX(shrel->link)];
110 struct sheader *toreloc = &sh[SHINDEX(shrel->info)];
112 struct symbol *symtab = (struct symbol *)(unsigned long)shsymtab->addr;
113 struct relo *rel = (struct relo *)(unsigned long)shrel->addr;
114 /* Early cast to unsigned long omits __udivdi3 call in x86-64 native bootstrap */
115 unsigned int numrel = (unsigned long)shrel->size / (unsigned long)shrel->entsize;
116 unsigned int i;
118 struct symbol *SysBase_sym = NULL;
121 * Ignore relocs if the target section has no allocation. that can happen
122 * eg. with a .debug PROGBITS and a .rel.debug section
124 if (!(toreloc->flags & SHF_ALLOC))
125 return 1;
127 DREL(kprintf("[ELF Loader] performing %d relocations\n", numrel));
129 for (i=0; i<numrel; i++, rel++)
131 struct symbol *sym = &symtab[ELF_R_SYM(rel->info)];
132 unsigned long *p = (void *)(unsigned long)toreloc->addr + rel->offset;
133 const char *name = (const char *)(unsigned long)sh[shsymtab->link].addr + sym->name;
134 elf_uintptr_t s;
136 #ifdef __arm__
138 * R_ARM_V4BX are actually special marks for the linker.
139 * They even never have a target (shindex == SHN_UNDEF),
140 * so we simply ignore them before doing any checks.
142 if (ELF_R_TYPE(rel->info) == R_ARM_V4BX)
143 continue;
144 #endif
146 switch (sym->shindex)
148 case SHN_UNDEF:
149 DREL(kprintf("[ELF Loader] Undefined symbol '%s'\n", name));
150 return 0;
152 case SHN_COMMON:
153 DREL(kprintf("[ELF Loader] COMMON symbol '%s'\n", name));
154 return 0;
156 case SHN_ABS:
157 if (SysBase_sym == NULL)
159 if (strncmp(name, "SysBase", 8) == 0)
161 DREL(kprintf("[ELF Loader] got SysBase\n"));
162 SysBase_sym = sym;
166 if (SysBase_sym == sym)
168 if (!SysBase_ptr)
170 SysBase_ptr = DefSysBase;
171 D(kprintf("[ELF Loader] SysBase pointer set to default %p\n", (void *)SysBase_ptr));
174 s = SysBase_ptr;
176 else
177 s = sym->value;
178 break;
180 default:
181 s = (uintptr_t)sh[sym->shindex].addr + sym->value;
183 if (!SysBase_ptr)
186 * The first global data symbol named SysBase becomes global SysBase.
187 * The idea behind: the first module (kernel.resource) contains global
188 * SysBase variable and all other modules are linked to it.
190 if (sym->info == ELF_S_INFO(STB_GLOBAL, STT_OBJECT))
192 if (strcmp(name, "SysBase") == 0)
194 SysBase_ptr = s;
195 D(kprintf("[ELF Loader] SysBase pointer set to %p\n", (void *)SysBase_ptr));
201 DREL(kprintf("[ELF Loader] Relocating symbol %s type ", sym->name ? name : "<unknown>"));
202 switch (ELF_R_TYPE(rel->info))
204 #ifdef ELF_64BIT
205 case R_X86_64_64: /* 64bit direct/absolute */
206 *(uint64_t *)p = s + rel->addend;
207 break;
209 case R_X86_64_PC32: /* PC relative 32 bit signed */
210 *(uint32_t *)p = s + rel->addend - (uintptr_t) p;
211 break;
213 case R_X86_64_32:
214 *(uint32_t *)p = (uint64_t)s + (uint64_t)rel->addend;
215 break;
217 case R_X86_64_32S:
218 *(int32_t *)p = (int64_t)s + (int64_t)rel->addend;
219 break;
221 case R_X86_64_NONE: /* No reloc */
222 break;
223 #else
224 #ifdef __i386__
225 case R_386_32: /* 32bit absolute */
226 DREL(kprintf("R_386_32"));
227 *p += s;
228 break;
230 case R_386_PC32: /* 32bit PC relative */
231 DREL(kprintf("R_386_PC32"));
232 *p += (s - (uintptr_t)p);
233 break;
235 case R_386_NONE:
236 DREL(kprintf("R_386_NONE"));
237 break;
238 #endif
239 #endif
240 #ifdef __mc68000__
241 case R_68K_32:
242 *p = s + rel->addend;
243 break;
245 case R_68K_PC32:
246 *p = s + rel->addend - (uint32_t)p;
247 break;
249 case R_68k_NONE:
250 break;
251 #endif
252 #if defined(__ppc__) || defined(__powerpc__)
253 case R_PPC_ADDR32:
254 *p = s + rel->addend;
255 break;
257 case R_PPC_ADDR16_LO:
259 unsigned short *c = (unsigned short *) p;
260 *c = (s + rel->addend) & 0xffff;
262 break;
264 case R_PPC_ADDR16_HA:
266 unsigned short *c = (unsigned short *) p;
267 uint32_t temp = s + rel->addend;
268 *c = temp >> 16;
269 if ((temp & 0x8000) != 0)
270 (*c)++;
272 break;
274 case R_PPC_REL16_LO:
276 unsigned short *c = (unsigned short *) p;
277 *c = (s + rel->addend - (uint32_t)p) & 0xffff;
279 break;
281 case R_PPC_REL16_HA:
283 unsigned short *c = (unsigned short *) p;
284 uint32_t temp = s + rel->addend - (uint32_t)p;
285 *c = temp >> 16;
286 if ((temp & 0x8000) != 0)
287 (*c)++;
289 break;
291 case R_PPC_REL24:
292 *p &= ~0x3fffffc;
293 *p |= (s + rel->addend - (uint32_t)p) & 0x3fffffc;
294 break;
296 case R_PPC_REL32:
297 *p = s + rel->addend - (uint32_t)p;
298 break;
300 case R_PPC_NONE:
301 break;
302 #endif
303 #ifdef __arm__
304 case R_ARM_CALL:
305 case R_ARM_JUMP24:
306 case R_ARM_PC24:
308 /* On ARM the 24 bit offset is shifted by 2 to the right */
309 signed long offset = (*p & 0x00ffffff) << 2;
310 /* If highest bit set, make offset negative */
311 if (offset & 0x02000000)
312 offset -= 0x04000000;
314 offset += s - (uint32_t)p;
316 offset >>= 2;
317 *p &= 0xff000000;
318 *p |= offset & 0x00ffffff;
320 break;
322 case R_ARM_MOVW_ABS_NC:
323 case R_ARM_MOVT_ABS:
325 signed long offset = *p;
326 offset = ((offset & 0xf0000) >> 4) | (offset & 0xfff);
327 offset = (offset ^ 0x8000) - 0x8000;
329 offset += s;
331 if (ELF_R_TYPE(rel->info) == R_ARM_MOVT_ABS)
332 offset >>= 16;
334 *p &= 0xfff0f000;
335 *p |= ((offset & 0xf000) << 4) | (offset & 0x0fff);
337 break;
339 case R_ARM_ABS32:
340 *p += s;
341 break;
343 case R_ARM_NONE:
344 break;
345 #endif
346 default:
347 kprintf("[ELF Loader] Unrecognized relocation type %d %ld\n", i, (long)ELF_R_TYPE(rel->info));
348 return 0;
350 DREL(kprintf(" -> %p\n", *p));
352 return 1;
355 int GetKernelSize(struct ELFNode *FirstELF, unsigned long *ro_size, unsigned long *rw_size, unsigned long *bss_size)
357 struct ELFNode *n;
358 unsigned long ksize = 0;
359 unsigned long rwsize = 0;
360 unsigned long bsize = sizeof(struct KernelBSS_t);
361 unsigned short i;
363 kprintf("[ELF Loader] Calculating kickstart size...\n");
365 for (n = FirstELF; n; n = n->Next)
367 void *file;
368 char *errstr = NULL;
369 unsigned int err;
371 D(kprintf("[ELF Loader] Checking file %s\n", n->Name));
373 file = open_file(n, &err);
374 if (err)
376 DisplayError("Failed to open file %s!\n", n->Name);
377 return 0;
380 /* Check the header of ELF file */
381 n->eh = load_block(file, 0, sizeof(struct elfheader), &err);
382 if (err)
384 errstr = "Failed to read file header";
386 else
388 errstr = check_header(n->eh);
389 if (!errstr)
391 n->sh = load_block(file, n->eh->shoff, n->eh->shnum * n->eh->shentsize, &err);
392 if (err)
394 errstr = "Failed to read section headers";
399 close_file(file);
400 if (errstr)
402 DisplayError("%s: %s\n", n->Name, errstr);
403 return 0;
407 * Debug data for the module includes:
408 * - Module descriptor (struct ELF_ModuleInfo_t)
409 * - ELF file header
410 * - ELF section header
411 * - File name
412 * - One empty pointer for alignment
414 ksize += (sizeof(struct ELF_ModuleInfo_t) + sizeof(struct elfheader) + n->eh->shnum * n->eh->shentsize +
415 strlen(n->Name) + sizeof(void *));
417 /* Go through all sections and calculate kernel size */
418 for(i = 0; i < n->eh->shnum; i++)
420 /* Ignore sections with zero lengths */
421 if (!n->sh[i].size)
422 continue;
425 * We will load:
426 * - Actual code and data (allocated sections)
427 * - String tables (for debug data)
428 * - Symbol tables (for debug data)
430 if ((n->sh[i].flags & SHF_ALLOC) || (n->sh[i].type == SHT_STRTAB) || (n->sh[i].type == SHT_SYMTAB))
432 /* Add maximum space for alignment */
433 unsigned long s = n->sh[i].size + n->sh[i].addralign - 1;
435 if (n->sh[i].flags & SHF_WRITE)
436 rwsize += s;
437 else
438 ksize += s;
440 if (n->sh[i].type == SHT_NOBITS)
441 bsize += sizeof(struct KernelBSS_t);
446 *ro_size = ksize;
447 *rw_size = rwsize;
449 if (bss_size)
450 *bss_size = bsize;
452 kprintf("[ELF Loader] Code %lu bytes, data %lu bytes, BSS array %lu bytes\n", ksize, rwsize, bsize);
454 return 1;
458 * This function loads the listed modules.
459 * It expects that ELF and section header pointers in the list are already set up by GetKernelSize().
461 * (elf_ptr_t)(unsigned long) double-casting is needed because in some cases elf_ptr_t is an UQUAD,
462 * while in most cases it's a pointer (see dos/elf.h).
464 int LoadKernel(struct ELFNode *FirstELF, void *ptr_ro, void *ptr_rw, void *tracker, uintptr_t DefSysBase,
465 void **kick_end, kernel_entry_fun_t *kernel_entry, struct ELF_ModuleInfo **kernel_debug)
467 struct ELFNode *n;
468 unsigned int i;
469 unsigned char need_entry = 1;
470 struct ELF_ModuleInfo_t *mod;
471 struct ELF_ModuleInfo_t *prev_mod = NULL;
473 kprintf("[ELF Loader] Loading kickstart...\n");
475 for (n = FirstELF; n; n = n->Next)
477 void *file;
478 unsigned int err;
480 kprintf("[ELF Loader] Code %p, Data %p, Module %s...\n", ptr_ro, ptr_rw, n->Name);
482 file = open_file(n, &err);
483 if (err)
485 DisplayError("Failed to open file %s!\n", n->Name);
486 return 0;
489 /* Iterate over the section header in order to load some hunks */
490 for (i=0; i < n->eh->shnum; i++)
492 struct sheader *sh = n->sh;
494 D(kprintf("[ELF Loader] Section %u... ", i));
496 if ((sh[i].flags & SHF_ALLOC) || (sh[i].type == SHT_STRTAB) || (sh[i].type == SHT_SYMTAB))
498 /* Does the section require memory allcation? */
499 D(kprintf("Allocated section\n"));
501 if (sh[i].flags & SHF_WRITE)
503 ptr_rw = load_hunk(file, &sh[i], (void *)ptr_rw, (struct KernelBSS_t **)&tracker);
504 if (!ptr_rw)
506 DisplayError("%s: Error loading hunk %u!\n", n->Name, i);
507 return 0;
510 else
512 ptr_ro = load_hunk(file, &sh[i], (void *)ptr_ro, (struct KernelBSS_t **)&tracker);
513 if (!ptr_ro)
515 DisplayError("%s: Error loading hunk %u!\n", n->Name, i);
516 return 0;
520 /* Remember address of the first code section, this is our entry point */
521 if ((sh[i].flags & SHF_EXECINSTR) && need_entry)
523 *kernel_entry = (void *)(unsigned long)sh[i].addr;
524 need_entry = 0;
527 D(else kprintf("Ignored\n");)
529 D(kprintf("[ELF Loader] Section address: %p, size: %lu\n", sh[i].addr, sh[i].size));
532 /* For every loaded section perform relocations */
533 D(kprintf("[ELF Loader] Relocating...\n"));
534 for (i=0; i < n->eh->shnum; i++)
536 struct sheader *sh = n->sh;
538 if ((sh[i].type == AROS_ELF_REL) && sh[sh[i].info].addr)
540 sh[i].addr = (elf_ptr_t)(unsigned long)load_block(file, sh[i].offset, sh[i].size, &err);
541 if (err)
543 DisplayError("%s: Failed to load relocation section %u\n", n->Name, i);
544 return 0;
547 if (!relocate(n->eh, sh, i, (uintptr_t)DefSysBase))
549 DisplayError("%s: Relocation error in section %u!\n", n->Name, i);
550 return 0;
553 free_block((void *)(unsigned long)sh[i].addr);
554 sh[i].addr = (elf_ptr_t)0;
558 close_file(file);
560 D(kprintf("[ELF Loader] Adding module debug information...\n"));
562 /* Align our pointer */
563 ptr_ro = (void *)(((unsigned long)ptr_ro + sizeof(void *)) & ~(sizeof(void *) - 1));
565 /* Allocate module descriptor */
566 mod = ptr_ro;
567 ptr_ro += sizeof(struct ELF_ModuleInfo_t);
568 mod->Next = 0;
569 mod->Type = DEBUG_ELF;
571 /* Copy ELF header */
572 mod->eh = (unsigned long)ptr_ro;
573 ptr_ro = copy_data(n->eh, ptr_ro, sizeof(struct elfheader));
575 /* Copy section header */
576 mod->sh = (unsigned long)ptr_ro;
577 ptr_ro = copy_data(n->sh, ptr_ro, n->eh->shnum * n->eh->shentsize);
579 /* Copy module name */
580 mod->Name = (unsigned long)ptr_ro;
581 ptr_ro = copy_data(n->Name, ptr_ro, strlen(n->Name) + 1);
583 /* Link the module descriptor with previous one */
584 if (prev_mod)
585 prev_mod->Next = (unsigned long)mod;
586 else
587 *kernel_debug = (struct ELF_ModuleInfo *)mod;
588 prev_mod = mod;
590 free_block(n->sh);
591 free_block(n->eh);
594 /* Terminate the array of BSS sections */
595 ((struct KernelBSS_t *)tracker)->addr = 0;
596 ((struct KernelBSS_t *)tracker)->len = 0;
598 /* Return end of kickstart read-only area if requested */
599 if (kick_end)
600 *kick_end = ptr_ro;
602 return 1;