Forward compatibility: build relative-base link libraries where needed
[AROS.git] / arch / ppc-chrp / dos / internalloadseg_elf.c
blob393ee11166d03990444c4f7da7822f580437e456
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Code to dynamically load ELF executables
6 Lang: english
8 1997/12/13: Changed filename to internalloadseg_elf.c
9 Original file was created by digulla.
12 #define DEBUG 0
14 #include <aros/config.h>
15 #include <aros/kernel.h>
16 #include <exec/memory.h>
17 #include <proto/exec.h>
18 #include <dos/elf.h>
19 #include <dos/dosasl.h>
20 #include <proto/dos.h>
21 #include <proto/arossupport.h>
22 #include <proto/kernel.h>
23 #include <aros/asmcall.h>
24 #include "internalloadseg.h"
25 #include "dos_intern.h"
27 #include <aros/debug.h>
28 #include <string.h>
29 #include <stddef.h>
31 #include <aros/macros.h>
33 struct hunk
35 ULONG size;
36 BPTR next;
37 char data[0];
38 } __attribute__((packed));
40 #define BPTR2HUNK(bptr) ((struct hunk *)((void *)bptr - offsetof(struct hunk, next)))
41 #define HUNK2BPTR(hunk) MKBADDR(&hunk->next)
43 static int elf_read_block
45 BPTR file,
46 ULONG offset,
47 APTR buffer,
48 ULONG size,
49 SIPTR *funcarray,
50 struct DosLibrary *DOSBase
53 UBYTE *buf = (UBYTE *)buffer;
54 LONG subsize;
56 if (ilsSeek(file, offset, OFFSET_BEGINNING) < 0)
57 return 0;
59 while (size)
61 subsize = ilsRead(file, buf, size);
63 if (subsize <= 0)
65 if (subsize == 0)
66 SetIoErr(ERROR_BAD_HUNK);
68 return 0;
71 buf += subsize;
72 size -= subsize;
75 return 1;
78 static void *load_block
80 BPTR file,
81 ULONG offset,
82 ULONG size,
83 SIPTR *funcarray,
84 struct DosLibrary *DOSBase
87 D(bug("[ELF Loader] Load Block\n"));
88 D(bug("[ELF Loader] (size=%d)\n",size));
89 D(bug("[ELF Loader] (funcarray=0x%x)\n",funcarray));
90 D(bug("[ELF Loader] (funcarray[1]=0x%x)\n",funcarray[1]));
91 void *block = ilsAllocMem(size, MEMF_ANY);
92 if (block)
94 if (elf_read_block(file, offset, block, size, funcarray, DOSBase))
95 return block;
97 ilsFreeMem(block, size);
99 else
100 SetIoErr(ERROR_NO_FREE_STORE);
102 return NULL;
105 static ULONG read_shnum(BPTR file, struct elfheader *eh, SIPTR *funcarray, struct DosLibrary *DOSBase)
107 ULONG shnum = eh->shnum;
109 /* the ELF header only uses 16 bits to store the count of section headers,
110 * so it can't handle more than 65535 headers. if the count is 0, and an
111 * offset is defined, then the real count can be found in the first
112 * section header (which always exists).
114 * similarly, if the string table index is SHN_XINDEX, then the actual
115 * index is found in the first section header also.
117 * see the System V ABI 2001-04-24 draft for more details.
119 if (eh->shnum == 0)
121 struct sheader sh;
123 if (eh->shoff == 0) {
124 SetIoErr(ERROR_NOT_EXECUTABLE);
125 return 0;
128 if (!elf_read_block(file, eh->shoff, &sh, sizeof(sh), funcarray, DOSBase))
129 return 0;
131 /* wider section header count is in the size field */
132 shnum = sh.size;
134 /* sanity, if they're still invalid then this isn't elf */
135 if (shnum == 0)
136 SetIoErr(ERROR_NOT_EXECUTABLE);
139 return shnum;
142 static void register_elf(BPTR file, BPTR hunks, struct elfheader *eh, struct sheader *sh, struct DosLibrary *DOSBase)
144 #ifdef KrnRegisterModule
145 APTR KernelBase = OpenResource("kernel.resource");
147 if (KernelBase)
149 char buffer[512];
151 if (NameFromFH(file, buffer, sizeof(buffer))) {
152 char *nameptr = buffer;
153 // struct ELF_DebugInfo dbg = {eh, sh};
155 /* gdb support needs full paths */
156 #if !AROS_MODULES_DEBUG
157 /* First, go through the name, till end of the string */
158 while(*nameptr++);
159 /* Now, go back until either ":" or "/" is found */
160 while(nameptr > buffer && nameptr[-1] != ':' && nameptr[-1] != '/')
161 nameptr--;
162 #endif
163 KrnRegisterModule(nameptr, sh, &eh);
164 //KrnRegisterModule(nameptr, hunks, DEBUG_ELF, &dbg);
167 #endif
170 static int load_header(BPTR file, struct elfheader *eh, SIPTR *funcarray, struct DosLibrary *DOSBase) {
171 ilsSeek(file, OFFSET_BEGINNING, 0);
172 if (!elf_read_block(file, 0, eh, sizeof(struct elfheader), funcarray, DOSBase))
173 return 0;
175 if (eh->ident[0] != 0x7f || eh->ident[1] != 'E' ||
176 eh->ident[2] != 'L' || eh->ident[3] != 'F') {
177 D(bug("[ELF Loader] Not an ELF object\n"));
178 SetIoErr(ERROR_NOT_EXECUTABLE);
179 return 0;
181 D(bug("[ELF Loader] ELF object\n"));
183 /* WANT_CLASS should be defined for your target */
184 if (eh->ident[EI_CLASS] != AROS_ELF_CLASS ||
185 eh->ident[EI_VERSION] != EV_CURRENT ||
186 eh->type != ET_REL ||
187 eh->ident[EI_DATA] != AROS_ELF_DATA ||
188 eh->machine != AROS_ELF_MACHINE)
190 D(bug("[ELF Loader] Object is of wrong type\n"));
191 D(bug("[ELF Loader] EI_CLASS is %d - should be %d\n", eh->ident[EI_CLASS] , AROS_ELF_CLASS ));
192 D(bug("[ELF Loader] EI_VERSION is %d - should be %d\n", eh->ident[EI_VERSION], EV_CURRENT ));
193 D(bug("[ELF Loader] type is %d - should be %d\n", eh->type , ET_REL ));
194 D(bug("[ELF Loader] EI_DATA is %d - should be %d\n", eh->ident[EI_DATA] , AROS_ELF_DATA ));
195 D(bug("[ELF Loader] machine is %d - should be %d\n", eh->machine , AROS_ELF_MACHINE));
197 SetIoErr(ERROR_NOT_EXECUTABLE);
198 return 0;
201 return 1;
204 static int load_hunk
206 BPTR file,
207 BPTR **next_hunk_ptr,
208 struct sheader *sh,
209 SIPTR *funcarray,
210 BOOL do_align,
211 struct DosLibrary *DOSBase
214 struct hunk *hunk;
215 ULONG hunk_size;
217 if (!sh->size)
218 return 1;
220 /* The size of the hunk is the size of the section, plus
221 the size of the hunk structure, plus the size of the alignment (if necessary)*/
222 hunk_size = sh->size + sizeof(struct hunk);
224 if (do_align)
226 hunk_size += sh->addralign;
228 /* Also create space for a trampoline, if necessary */
229 if (sh->flags & SHF_EXECINSTR)
230 hunk_size += sizeof(struct FullJumpVec);
233 hunk = ilsAllocMem(hunk_size, MEMF_ANY | (sh->type == SHT_NOBITS) ? MEMF_CLEAR : 0);
234 if (hunk)
236 hunk->next = 0;
237 hunk->size = hunk_size;
239 /* In case we are required to honour alignment, and If this section contains
240 executable code, create a trampoline to its beginning, so that even if the
241 alignment requirements make the actual code go much after the end of the
242 hunk structure, the code can still be reached in the usual way. */
243 if (do_align)
245 if (sh->flags & SHF_EXECINSTR)
247 sh->addr = (char *)AROS_ROUNDUP2
249 (IPTR)hunk->data + sizeof(struct FullJumpVec), sh->addralign
251 __AROS_SET_FULLJMP((struct FullJumpVec *)hunk->data, sh->addr);
253 else
254 sh->addr = (char *)AROS_ROUNDUP2((IPTR)hunk->data, sh->addralign);
256 else
257 sh->addr = hunk->data;
259 /* Link the previous one with the new one */
260 BPTR2HUNK(*next_hunk_ptr)->next = HUNK2BPTR(hunk);
262 D(bug("[dos] hunk @ %p, size=%08x, addr @ %p\n", hunk, hunk->size, sh->addr));
264 /* Update the pointer to the previous one, which is now the current one */
265 *next_hunk_ptr = &hunk->next;
267 if (sh->type != SHT_NOBITS)
268 return elf_read_block(file, sh->offset, sh->addr, sh->size, funcarray, DOSBase);
270 return 1;
274 SetIoErr(ERROR_NO_FREE_STORE);
276 return 0;
279 static int relocate
281 struct elfheader *eh,
282 struct sheader *sh,
283 ULONG shrel_idx,
284 struct sheader *symtab_shndx,
285 struct DosLibrary *DOSBase
288 struct sheader *shrel = &sh[shrel_idx];
289 struct sheader *shsymtab = &sh[shrel->link];
290 struct sheader *toreloc = &sh[shrel->info];
292 struct symbol *symtab = (struct symbol *)shsymtab->addr;
293 struct relo *rel = (struct relo *)shrel->addr;
296 * Ignore relocs if the target section has no allocation. that can happen
297 * eg. with a .debug PROGBITS and a .rel.debug section
299 if (!(toreloc->flags & SHF_ALLOC))
300 return 1;
302 ULONG numrel = shrel->size / shrel->entsize;
303 ULONG i;
305 struct symbol *SysBase_sym = NULL;
307 for (i=0; i<numrel; i++, rel++)
309 struct symbol *sym;
310 ULONG *p;
311 IPTR s;
312 ULONG shindex;
314 #ifdef __arm__
316 * R_ARM_V4BX are actually special marks for the linker.
317 * They even never have a target (shindex == SHN_UNDEF),
318 * so we simply ignore them before doing any checks.
320 if (ELF_R_TYPE(rel->info) == R_ARM_V4BX)
321 continue;
322 #endif
324 sym = &symtab[ELF_R_SYM(rel->info)];
325 p = toreloc->addr + rel->offset;
327 if (sym->shindex != SHN_XINDEX)
328 shindex = sym->shindex;
330 else {
331 if (symtab_shndx == NULL) {
332 D(bug("[ELF Loader] got symbol with shndx 0xfff, but there's no symtab shndx table\n"));
333 SetIoErr(ERROR_BAD_HUNK);
334 return 0;
336 shindex = ((ULONG *)symtab_shndx->addr)[ELF_R_SYM(rel->info)];
339 DB2(bug("[ELF Loader] Processing symbol %s\n", sh[shsymtab->link].addr + sym->name));
341 switch (shindex)
344 case SHN_UNDEF:
345 D(bug("[ELF Loader] Undefined symbol '%s'\n",
346 (STRPTR)sh[shsymtab->link].addr + sym->name));
347 SetIoErr(ERROR_BAD_HUNK);
348 return 0;
350 case SHN_COMMON:
351 D(bug("[ELF Loader] COMMON symbol '%s'\n",
352 (STRPTR)sh[shsymtab->link].addr + sym->name));
353 SetIoErr(ERROR_BAD_HUNK);
355 return 0;
357 case SHN_ABS:
358 if (SysBase_sym == NULL)
360 if (strncmp((STRPTR)sh[shsymtab->link].addr + sym->name, "SysBase", 8) == 0)
362 SysBase_sym = sym;
363 goto SysBase_yes;
365 else
366 goto SysBase_no;
368 else
369 if (SysBase_sym == sym)
371 SysBase_yes: s = (IPTR)&SysBase;
373 else
374 SysBase_no: s = sym->value;
375 break;
377 default:
378 s = (IPTR)sh[shindex].addr + sym->value;
381 switch (ELF_R_TYPE(rel->info))
383 #if defined(__i386__)
385 case R_386_32: /* 32bit absolute */
386 *p += s;
387 break;
389 case R_386_PC32: /* 32bit PC relative */
390 *p += s - (ULONG)p;
391 break;
393 case R_386_NONE:
394 break;
396 #elif defined(__x86_64__)
397 case R_X86_64_64: /* 64bit direct/absolute */
398 *(UQUAD *)p = s + rel->addend;
399 break;
401 case R_X86_64_PC32: /* PC relative 32 bit signed */
402 *(ULONG *)p = s + rel->addend - (IPTR) p;
403 break;
405 case R_X86_64_32:
406 *(ULONG *)p = (UQUAD)s + (UQUAD)rel->addend;
407 break;
409 case R_X86_64_32S:
410 *(LONG *)p = (QUAD)s + (QUAD)rel->addend;
411 break;
413 case R_X86_64_NONE: /* No reloc */
414 break;
416 #elif defined(__mc68000__)
418 case R_68K_32:
419 *p = s + rel->addend;
420 break;
422 case R_68K_PC32:
423 *p = s + rel->addend - (ULONG)p;
424 break;
426 case R_68k_NONE:
427 break;
429 #elif defined(__ppc__) || defined(__powerpc__)
431 case R_PPC_ADDR32:
432 *p = s + rel->addend;
433 break;
435 case R_PPC_ADDR16_LO:
437 unsigned short *c = (unsigned short *) p;
438 *c = (s + rel->addend) & 0xffff;
440 break;
442 case R_PPC_ADDR16_HA:
444 unsigned short *c = (unsigned short *) p;
445 ULONG temp = s + rel->addend;
446 *c = temp >> 16;
447 if ((temp & 0x8000) != 0)
448 (*c)++;
450 break;
452 case R_PPC_REL16_LO:
454 unsigned short *c = (unsigned short *) p;
455 *c = (s + rel->addend - (ULONG) p) & 0xffff;
457 break;
459 case R_PPC_REL16_HA:
461 unsigned short *c = (unsigned short *) p;
462 ULONG temp = s + rel->addend - (ULONG) p;
463 *c = temp >> 16;
464 if ((temp & 0x8000) != 0)
465 (*c)++;
467 break;
469 case R_PPC_REL24:
470 *p &= ~0x3fffffc;
471 *p |= (s + rel->addend - (ULONG) p) & 0x3fffffc;
472 break;
474 case R_PPC_REL32:
475 *p = s + rel->addend - (ULONG) p;
476 break;
478 case R_PPC_NONE:
479 break;
481 #elif defined(__arm__)
482 case R_ARM_CALL:
483 case R_ARM_JUMP24:
484 case R_ARM_PC24:
486 /* On ARM the 24 bit offset is shifted by 2 to the right */
487 signed long offset = (*p & 0x00ffffff) << 2;
488 /* If highest bit set, make offset negative */
489 if (offset & 0x02000000)
490 offset -= 0x04000000;
492 offset += s - (uint32_t)p;
494 offset >>= 2;
495 *p &= 0xff000000;
496 *p |= offset & 0x00ffffff;
498 break;
500 case R_ARM_MOVW_ABS_NC:
501 case R_ARM_MOVT_ABS:
503 signed long offset = *p;
504 offset = ((offset & 0xf0000) >> 4) | (offset & 0xfff);
505 offset = (offset ^ 0x8000) - 0x8000;
507 offset += s;
509 if (ELF_R_TYPE(rel->info) == R_ARM_MOVT_ABS)
510 offset >>= 16;
512 *p &= 0xfff0f000;
513 *p |= ((offset & 0xf000) << 4) | (offset & 0x0fff);
515 break;
517 case R_ARM_ABS32:
518 *p += s;
519 break;
521 case R_ARM_NONE:
522 break;
524 #else
525 # error Your architecture is not supported
526 #endif
528 default:
529 D(bug("[ELF Loader] Unrecognized relocation type %d %d\n", i, ELF_R_TYPE(rel->info)));
530 SetIoErr(ERROR_BAD_HUNK);
531 return 0;
535 return 1;
538 BPTR InternalLoadSeg_ELF
540 BPTR file,
541 BPTR table __unused,
542 SIPTR *funcarray,
543 LONG *stack __unused,
544 struct DosLibrary *DOSBase
547 struct elfheader eh;
548 struct sheader *sh;
549 struct sheader *symtab_shndx = NULL;
550 BPTR hunks = 0;
551 BPTR *next_hunk_ptr = &hunks;
552 ULONG i;
553 BOOL exec_hunk_seen = FALSE;
554 ULONG int_shnum;
556 /* load and validate ELF header */
557 if (!load_header(file, &eh, funcarray, DOSBase))
558 return 0;
560 int_shnum = read_shnum(file, &eh, funcarray, DOSBase);
561 if (!int_shnum)
562 return 0;
564 /* load section headers */
565 if (!(sh = load_block(file, eh.shoff, int_shnum * eh.shentsize, funcarray, DOSBase)))
566 return 0;
568 /* Iterate over the section headers in order to do some stuff... */
569 for (i = 0; i < int_shnum; i++)
572 Load the symbol and string table(s).
574 NOTICE: the ELF standard, at the moment (Nov 2002) explicitely states
575 that only one symbol table per file is allowed. However, it
576 also states that this may change in future... we already handle it.
578 if (sh[i].type == SHT_SYMTAB || sh[i].type == SHT_STRTAB || sh[i].type == SHT_SYMTAB_SHNDX)
580 sh[i].addr = load_block(file, sh[i].offset, sh[i].size, funcarray, DOSBase);
581 if (!sh[i].addr)
582 goto error;
584 if (sh[i].type == SHT_SYMTAB_SHNDX) {
585 if (symtab_shndx == NULL)
586 symtab_shndx = &sh[i];
587 else
588 D(bug("[ELF Loader] file contains multiple symtab shndx tables. only using the first one\n"));
591 else
592 /* Load the section in memory if needed, and make an hunk out of it */
593 if (sh[i].flags & SHF_ALLOC)
595 if (sh[i].size)
597 /* Only allow alignment if this is an executable hunk
598 or if an executable hunk has been loaded already,
599 so to avoid the situation in which a data hunk has its
600 content displaced from the hunk's header in case it's the
601 first hunk (this happens with Keymaps, for instance). */
602 if (sh[i].flags & SHF_EXECINSTR)
603 exec_hunk_seen = TRUE;
605 if (!load_hunk(file, &next_hunk_ptr, &sh[i], funcarray, exec_hunk_seen, DOSBase))
606 goto error;
612 /* Relocate the sections */
613 for (i = 0; i < int_shnum; i++)
615 /* Does this relocation section refer to a hunk? If so, addr must be != 0 */
616 if ((sh[i].type == AROS_ELF_REL) && sh[sh[i].info].addr)
618 sh[i].addr = load_block(file, sh[i].offset, sh[i].size, funcarray, DOSBase);
619 if (!sh[i].addr || !relocate(&eh, sh, i, symtab_shndx, DOSBase))
620 goto error;
622 ilsFreeMem(sh[i].addr, sh[i].size);
623 sh[i].addr = NULL;
627 /* Everything is loaded now. Register the module at kernel.resource */
628 register_elf(file, hunks, &eh, sh, DOSBase);
629 goto end;
631 error:
633 /* There were some errors, deallocate The hunks */
635 InternalUnLoadSeg(hunks, (VOID_FUNC)funcarray[2]);
636 hunks = 0;
638 end:
640 /* Clear the caches to let the CPU see the new data and instructions */
642 BPTR curr = hunks;
643 while (curr)
645 struct hunk *hunk = BPTR2HUNK(BADDR(curr));
647 CacheClearE(hunk->data, hunk->size, CACRF_ClearD | CACRF_ClearI);
649 curr = hunk->next;
653 /* deallocate the symbol tables */
654 for (i = 0; i < int_shnum; i++)
656 if (((sh[i].type == SHT_SYMTAB) || (sh[i].type == SHT_STRTAB)) && (sh[i].addr != NULL))
657 ilsFreeMem(sh[i].addr, sh[i].size);
660 /* Free the section headers */
661 ilsFreeMem(sh, int_shnum * eh.shentsize);
663 return hunks;