Build fix.
[AROS.git] / rom / dos / internalloadseg_elf.c
blob0df718e2d3578bfb424d26a258466b9ca98061c3
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 #include <aros/asmcall.h>
13 #include <aros/config.h>
14 #include <aros/debug.h>
15 #include <aros/macros.h>
16 #include <exec/memory.h>
17 #include <dos/elf.h>
18 #include <dos/dosasl.h>
19 #include <libraries/debug.h>
20 #include <proto/dos.h>
21 #include <proto/arossupport.h>
22 #include <proto/debug.h>
23 #include <proto/exec.h>
25 #include <string.h>
26 #include <stddef.h>
28 #include "internalloadseg.h"
29 #include "dos_intern.h"
31 struct hunk
33 ULONG size;
34 BPTR next;
35 char data[0];
36 } __attribute__((packed));
38 #define BPTR2HUNK(bptr) ((struct hunk *)((void *)bptr - offsetof(struct hunk, next)))
39 #define HUNK2BPTR(hunk) MKBADDR(&hunk->next)
41 static int read_block
43 BPTR file,
44 ULONG offset,
45 APTR buffer,
46 ULONG size,
47 SIPTR *funcarray,
48 struct DosLibrary *DOSBase
51 UBYTE *buf = (UBYTE *)buffer;
52 LONG subsize;
54 if (ilsSeek(file, offset, OFFSET_BEGINNING) < 0)
55 return 0;
57 while (size)
59 subsize = ilsRead(file, buf, size);
61 if (subsize <= 0)
63 if (subsize == 0)
64 SetIoErr(ERROR_BAD_HUNK);
66 return 0;
69 buf += subsize;
70 size -= subsize;
73 return 1;
76 static void *load_block
78 BPTR file,
79 ULONG offset,
80 ULONG size,
81 SIPTR *funcarray,
82 struct DosLibrary *DOSBase
85 D(bug("[ELF Loader] Load Block\n"));
86 D(bug("[ELF Loader] (size=%d)\n",size));
87 D(bug("[ELF Loader] (funcarray=0x%x)\n",funcarray));
88 D(bug("[ELF Loader] (funcarray[1]=0x%x)\n",funcarray[1]));
89 void *block = ilsAllocMem(size, MEMF_ANY);
90 if (block)
92 if (read_block(file, offset, block, size, funcarray, DOSBase))
93 return block;
95 ilsFreeMem(block, size);
97 else
98 SetIoErr(ERROR_NO_FREE_STORE);
100 return NULL;
103 static ULONG read_shnum(BPTR file, struct elfheader *eh, SIPTR *funcarray, struct DosLibrary *DOSBase)
105 ULONG shnum = eh->shnum;
107 /* the ELF header only uses 16 bits to store the count of section headers,
108 * so it can't handle more than 65535 headers. if the count is 0, and an
109 * offset is defined, then the real count can be found in the first
110 * section header (which always exists).
112 * similarly, if the string table index is SHN_XINDEX, then the actual
113 * index is found in the first section header also.
115 * see the System V ABI 2001-04-24 draft for more details.
117 if (eh->shnum == 0)
119 struct sheader sh;
121 if (eh->shoff == 0) {
122 SetIoErr(ERROR_NOT_EXECUTABLE);
123 return 0;
126 if (!read_block(file, eh->shoff, &sh, sizeof(sh), funcarray, DOSBase))
127 return 0;
129 /* wider section header count is in the size field */
130 shnum = sh.size;
132 /* sanity, if they're still invalid then this isn't elf */
133 if (shnum == 0)
134 SetIoErr(ERROR_NOT_EXECUTABLE);
137 return shnum;
140 static void register_elf(BPTR file, BPTR hunks, struct elfheader *eh, struct sheader *sh, struct DosLibrary *DOSBase)
142 if (DebugBase)
144 char buffer[512];
146 if (NameFromFH(file, buffer, sizeof(buffer)))
148 char *nameptr = buffer;
149 struct ELF_DebugInfo dbg = {eh, sh};
151 /* gdb support needs full paths */
152 #if !AROS_MODULES_DEBUG
153 /* First, go through the name, till end of the string */
154 while(*nameptr++);
155 /* Now, go back until either ":" or "/" is found */
156 while(nameptr > buffer && nameptr[-1] != ':' && nameptr[-1] != '/')
157 nameptr--;
158 #endif
159 RegisterModule(nameptr, hunks, DEBUG_ELF, &dbg);
164 static int load_header(BPTR file, struct elfheader *eh, SIPTR *funcarray, struct DosLibrary *DOSBase) {
165 ilsSeek(file, OFFSET_BEGINNING, 0);
166 if (!read_block(file, 0, eh, sizeof(struct elfheader), funcarray, DOSBase))
167 return 0;
169 if (eh->ident[0] != 0x7f || eh->ident[1] != 'E' ||
170 eh->ident[2] != 'L' || eh->ident[3] != 'F') {
171 D(bug("[ELF Loader] Not an ELF object\n"));
172 SetIoErr(ERROR_NOT_EXECUTABLE);
173 return 0;
175 D(bug("[ELF Loader] ELF object\n"));
177 /* WANT_CLASS should be defined for your target */
178 if (eh->ident[EI_CLASS] != AROS_ELF_CLASS ||
179 eh->ident[EI_VERSION] != EV_CURRENT ||
180 eh->type != ET_REL ||
181 eh->ident[EI_DATA] != AROS_ELF_DATA ||
182 eh->machine != AROS_ELF_MACHINE)
184 D(bug("[ELF Loader] Object is of wrong type\n"));
185 D(bug("[ELF Loader] EI_CLASS is %d - should be %d\n", eh->ident[EI_CLASS] , AROS_ELF_CLASS ));
186 D(bug("[ELF Loader] EI_VERSION is %d - should be %d\n", eh->ident[EI_VERSION], EV_CURRENT ));
187 D(bug("[ELF Loader] type is %d - should be %d\n", eh->type , ET_REL ));
188 D(bug("[ELF Loader] EI_DATA is %d - should be %d\n", eh->ident[EI_DATA] , AROS_ELF_DATA ));
189 D(bug("[ELF Loader] machine is %d - should be %d\n", eh->machine , AROS_ELF_MACHINE));
191 SetIoErr(ERROR_NOT_EXECUTABLE);
192 return 0;
195 return 1;
198 static int load_hunk
200 BPTR file,
201 BPTR **next_hunk_ptr,
202 struct sheader *sh,
203 SIPTR *funcarray,
204 BOOL do_align,
205 struct DosLibrary *DOSBase
208 struct hunk *hunk;
209 ULONG hunk_size;
211 if (!sh->size)
212 return 1;
214 /* The size of the hunk is the size of the section, plus
215 the size of the hunk structure, plus the size of the alignment (if necessary)*/
216 hunk_size = sh->size + sizeof(struct hunk);
218 if (do_align)
220 hunk_size += sh->addralign;
222 /* Also create space for a trampoline, if necessary */
223 if (sh->flags & SHF_EXECINSTR)
224 hunk_size += sizeof(struct FullJumpVec);
227 hunk = ilsAllocMem(hunk_size, MEMF_ANY | (sh->type == SHT_NOBITS) ? MEMF_CLEAR : 0);
228 if (hunk)
230 hunk->next = 0;
231 hunk->size = hunk_size;
233 /* In case we are required to honour alignment, and If this section contains
234 executable code, create a trampoline to its beginning, so that even if the
235 alignment requirements make the actual code go much after the end of the
236 hunk structure, the code can still be reached in the usual way. */
237 if (do_align)
239 if (sh->flags & SHF_EXECINSTR)
241 sh->addr = (char *)AROS_ROUNDUP2
243 (IPTR)hunk->data + sizeof(struct FullJumpVec), sh->addralign
245 __AROS_SET_FULLJMP((struct FullJumpVec *)hunk->data, sh->addr);
247 else
248 sh->addr = (char *)AROS_ROUNDUP2((IPTR)hunk->data, sh->addralign);
250 else
251 sh->addr = hunk->data;
253 /* Link the previous one with the new one */
254 BPTR2HUNK(*next_hunk_ptr)->next = HUNK2BPTR(hunk);
256 D(bug("[dos] hunk @ %p, size=%08x, addr @ %p\n", hunk, hunk->size, sh->addr));
258 /* Update the pointer to the previous one, which is now the current one */
259 *next_hunk_ptr = &hunk->next;
261 if (sh->type != SHT_NOBITS)
262 return read_block(file, sh->offset, sh->addr, sh->size, funcarray, DOSBase);
264 return 1;
268 SetIoErr(ERROR_NO_FREE_STORE);
270 return 0;
273 static int relocate
275 struct elfheader *eh,
276 struct sheader *sh,
277 ULONG shrel_idx,
278 struct sheader *symtab_shndx,
279 struct DosLibrary *DOSBase
282 struct sheader *shrel = &sh[shrel_idx];
283 struct sheader *shsymtab = &sh[SHINDEX(shrel->link)];
284 struct sheader *toreloc = &sh[SHINDEX(shrel->info)];
286 struct symbol *symtab = (struct symbol *)shsymtab->addr;
287 struct relo *rel = (struct relo *)shrel->addr;
290 * Ignore relocs if the target section has no allocation. that can happen
291 * eg. with a .debug PROGBITS and a .rel.debug section
293 if (!(toreloc->flags & SHF_ALLOC))
294 return 1;
296 ULONG numrel = shrel->size / shrel->entsize;
297 ULONG i;
299 #ifndef NO_SYSBASE_REMAP
300 struct symbol *SysBase_sym = NULL;
301 #endif
303 for (i=0; i<numrel; i++, rel++)
305 struct symbol *sym;
306 ULONG *p;
307 IPTR s;
308 ULONG shindex;
310 #ifdef __arm__
312 * R_ARM_V4BX are actually special marks for the linker.
313 * They even never have a target (shindex == SHN_UNDEF),
314 * so we simply ignore them before doing any checks.
316 if (ELF_R_TYPE(rel->info) == R_ARM_V4BX)
317 continue;
318 #endif
320 sym = &symtab[ELF_R_SYM(rel->info)];
321 p = toreloc->addr + rel->offset;
323 if (sym->shindex != SHN_XINDEX)
324 shindex = sym->shindex;
326 else {
327 if (symtab_shndx == NULL) {
328 D(bug("[ELF Loader] got symbol with shndx 0xfff, but there's no symtab shndx table\n"));
329 SetIoErr(ERROR_BAD_HUNK);
330 return 0;
332 shindex = ((ULONG *)symtab_shndx->addr)[ELF_R_SYM(rel->info)];
335 DB2(bug("[ELF Loader] Processing symbol %s\n", sh[SHINDEX(shsymtab->link)].addr + sym->name));
337 switch (shindex)
340 case SHN_UNDEF:
341 D(bug("[ELF Loader] Undefined symbol '%s'\n",
342 (STRPTR)sh[SHINDEX(shsymtab->link)].addr + sym->name));
343 SetIoErr(ERROR_BAD_HUNK);
344 return 0;
346 case SHN_COMMON:
347 D(bug("[ELF Loader] COMMON symbol '%s'\n",
348 (STRPTR)sh[SHINDEX(shsymtab->link)].addr + sym->name));
349 SetIoErr(ERROR_BAD_HUNK);
351 return 0;
353 case SHN_ABS:
354 #ifdef NO_SYSBASE_REMAP
355 s = sym->value;
356 #else
357 if (SysBase_sym == NULL)
359 if (strncmp((STRPTR)sh[SHINDEX(shsymtab->link)].addr + sym->name, "SysBase", 8) == 0)
361 SysBase_sym = sym;
362 goto SysBase_yes;
364 else
365 goto SysBase_no;
367 else
368 if (SysBase_sym == sym)
370 SysBase_yes: s = (IPTR)&SysBase;
372 else
373 SysBase_no: s = sym->value;
374 #endif
375 break;
377 default:
378 s = (IPTR)sh[SHINDEX(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_16:
423 *(UWORD *)p = s + rel->addend;
424 break;
426 case R_68K_8:
427 *(UBYTE *)p = s + rel->addend;
428 break;
430 case R_68K_PC32:
431 *p = s + rel->addend - (ULONG)p;
432 break;
434 case R_68K_PC16:
435 *(UWORD *)p = s + rel->addend - (ULONG)p;
436 break;
438 case R_68K_PC8:
439 *(UBYTE *)p = s + rel->addend - (ULONG)p;
440 break;
442 case R_68K_NONE:
443 break;
445 #elif defined(__ppc__) || defined(__powerpc__)
447 case R_PPC_ADDR32:
448 *p = s + rel->addend;
449 break;
451 case R_PPC_ADDR16_LO:
453 unsigned short *c = (unsigned short *) p;
454 *c = (s + rel->addend) & 0xffff;
456 break;
458 case R_PPC_ADDR16_HA:
460 unsigned short *c = (unsigned short *) p;
461 ULONG temp = s + rel->addend;
462 *c = temp >> 16;
463 if ((temp & 0x8000) != 0)
464 (*c)++;
466 break;
468 case R_PPC_REL16_LO:
470 unsigned short *c = (unsigned short *) p;
471 *c = (s + rel->addend - (ULONG) p) & 0xffff;
473 break;
475 case R_PPC_REL16_HA:
477 unsigned short *c = (unsigned short *) p;
478 ULONG temp = s + rel->addend - (ULONG) p;
479 *c = temp >> 16;
480 if ((temp & 0x8000) != 0)
481 (*c)++;
483 break;
485 case R_PPC_REL24:
486 *p &= ~0x3fffffc;
487 *p |= (s + rel->addend - (ULONG) p) & 0x3fffffc;
488 break;
490 case R_PPC_REL32:
491 *p = s + rel->addend - (ULONG) p;
492 break;
494 case R_PPC_NONE:
495 break;
497 #elif defined(__arm__)
498 case R_ARM_CALL:
499 case R_ARM_JUMP24:
500 case R_ARM_PC24:
502 /* On ARM the 24 bit offset is shifted by 2 to the right */
503 signed long offset = (*p & 0x00ffffff) << 2;
504 /* If highest bit set, make offset negative */
505 if (offset & 0x02000000)
506 offset -= 0x04000000;
508 if (offset >= 0x02000000 ||
509 offset <= -0x02000000)
511 bug("[ELF Loader] Relocation type %d %d out of range!\n", i, ELF_R_TYPE(rel->info));
512 SetIoErr(ERROR_BAD_HUNK);
513 return 0;
515 offset += s - (ULONG)p;
517 offset >>= 2;
518 *p &= 0xff000000;
519 *p |= offset & 0x00ffffff;
521 break;
523 case R_ARM_THM_CALL:
524 case R_ARM_THM_JUMP24:
526 ULONG upper,lower,sign,j1,j2;
527 LONG offset;
529 upper = *((UWORD *)p);
530 lower = *((UWORD *)p+1);
532 sign = (upper >> 10) & 1;
533 j1 = (lower >> 13) & 1;
534 j2 = (lower >> 11) & 1;
536 offset = (sign << 24) | ((~(j1 ^ sign) & 1) << 23) |
537 ((~(j2 ^ sign) & 1) << 22) |
538 ((upper & 0x03ff) << 12) |
539 ((lower & 0x07ff) << 1);
541 if (offset & 0x01000000)
542 offset -= 0x02000000;
544 if (offset >= 0x01000000 ||
545 offset <= -0x01000000)
547 bug("[ELF Loader] Relocation type %d %d out of range!\n", i, ELF_R_TYPE(rel->info));
548 SetIoErr(ERROR_BAD_HUNK);
549 return 0;
551 offset += s - (ULONG)p;
553 sign = (offset >> 24) & 1;
554 j1 = sign ^ (~(offset >> 23) & 1);
555 j2 = sign ^ (~(offset >> 22) & 1);
557 *(UWORD *)p = (UWORD)((upper & 0xf800) | (sign << 10) |
558 ((offset >> 12) & 0x03ff));
559 *((UWORD *)p + 1) = (UWORD)((lower & 0xd000) |
560 (j1 << 13) | (j2 << 11) | ((offset >> 1) & 0x07ff));
563 break;
565 case R_ARM_THM_MOVW_ABS_NC:
566 case R_ARM_THM_MOVT_ABS:
568 ULONG upper,lower;
569 LONG offset;
571 upper = *((UWORD *)p);
572 lower = *((UWORD *)p+1);
574 offset = ((upper & 0x000f) << 12) |
575 ((upper & 0x0400) << 1) |
576 ((lower & 0x7000) >> 4) |
577 (lower & 0x00ff);
579 offset = (offset ^ 0x8000) - 0x8000;
581 offset += s;
583 if (ELF_R_TYPE(rel->info) == R_ARM_THM_MOVT_ABS)
584 offset >>= 16;
586 *(UWORD *)p = (UWORD)((upper & 0xfbf0) |
587 ((offset & 0xf000) >> 12) |
588 ((offset & 0x0800) >> 1));
589 *((UWORD *)p + 1) = (UWORD)((lower & 0x8f00) |
590 ((offset & 0x0700)<< 4) |
591 (offset & 0x00ff));
593 break;
595 case R_ARM_MOVW_ABS_NC:
596 case R_ARM_MOVT_ABS:
598 signed long offset = *p;
599 offset = ((offset & 0xf0000) >> 4) | (offset & 0xfff);
600 offset = (offset ^ 0x8000) - 0x8000;
602 offset += s;
604 if (ELF_R_TYPE(rel->info) == R_ARM_MOVT_ABS)
605 offset >>= 16;
607 *p &= 0xfff0f000;
608 *p |= ((offset & 0xf000) << 4) | (offset & 0x0fff);
610 break;
612 case R_ARM_ABS32:
613 *p += s;
614 break;
616 case R_ARM_NONE:
617 break;
619 #else
620 # error Your architecture is not supported
621 #endif
623 default:
624 D(bug("[ELF Loader] Unrecognized relocation type %d %d\n", i, ELF_R_TYPE(rel->info)));
625 SetIoErr(ERROR_BAD_HUNK);
626 return 0;
630 return 1;
633 BPTR InternalLoadSeg_ELF
635 BPTR file,
636 BPTR table __unused,
637 SIPTR *funcarray,
638 LONG *stack __unused,
639 struct DosLibrary *DOSBase
642 struct elfheader eh;
643 struct sheader *sh;
644 struct sheader *symtab_shndx = NULL;
645 BPTR hunks = 0;
646 BPTR *next_hunk_ptr = &hunks;
647 ULONG i;
648 BOOL exec_hunk_seen = FALSE;
649 ULONG int_shnum;
651 /* load and validate ELF header */
652 if (!load_header(file, &eh, funcarray, DOSBase))
653 return 0;
655 int_shnum = read_shnum(file, &eh, funcarray, DOSBase);
656 if (!int_shnum)
657 return 0;
659 /* load section headers */
660 if (!(sh = load_block(file, eh.shoff, int_shnum * eh.shentsize, funcarray, DOSBase)))
661 return 0;
663 /* Iterate over the section headers in order to do some stuff... */
664 for (i = 0; i < int_shnum; i++)
667 Load the symbol and string table(s).
669 NOTICE: the ELF standard, at the moment (Nov 2002) explicitely states
670 that only one symbol table per file is allowed. However, it
671 also states that this may change in future... we already handle it.
673 if (sh[i].type == SHT_SYMTAB || sh[i].type == SHT_STRTAB || sh[i].type == SHT_SYMTAB_SHNDX)
675 sh[i].addr = load_block(file, sh[i].offset, sh[i].size, funcarray, DOSBase);
676 if (!sh[i].addr)
677 goto error;
679 if (sh[i].type == SHT_SYMTAB_SHNDX) {
680 if (symtab_shndx == NULL)
681 symtab_shndx = &sh[i];
682 else
683 D(bug("[ELF Loader] file contains multiple symtab shndx tables. only using the first one\n"));
686 else
687 /* Load the section in memory if needed, and make a hunk out of it */
688 if (sh[i].flags & SHF_ALLOC)
690 if (sh[i].size)
692 /* Only allow alignment if this is an executable hunk
693 or if an executable hunk has been loaded already,
694 so to avoid the situation in which a data hunk has its
695 content displaced from the hunk's header in case it's the
696 first hunk (this happens with Keymaps, for instance). */
697 if (sh[i].flags & SHF_EXECINSTR)
698 exec_hunk_seen = TRUE;
700 if (!load_hunk(file, &next_hunk_ptr, &sh[i], funcarray, exec_hunk_seen, DOSBase))
701 goto error;
707 /* Relocate the sections */
708 for (i = 0; i < int_shnum; i++)
710 /* Does this relocation section refer to a hunk? If so, addr must be != 0 */
711 if ((sh[i].type == AROS_ELF_REL) && sh[SHINDEX(sh[i].info)].addr)
713 sh[i].addr = load_block(file, sh[i].offset, sh[i].size, funcarray, DOSBase);
714 if (!sh[i].addr || !relocate(&eh, sh, i, symtab_shndx, DOSBase))
715 goto error;
717 ilsFreeMem(sh[i].addr, sh[i].size);
718 sh[i].addr = NULL;
722 /* Everything is loaded now. Register the module at kernel.resource */
723 register_elf(file, hunks, &eh, sh, DOSBase);
724 goto end;
726 error:
728 /* There were some errors, deallocate The hunks */
730 InternalUnLoadSeg(hunks, (VOID_FUNC)funcarray[2]);
731 hunks = 0;
733 end:
735 /* Clear the caches to let the CPU see the new data and instructions */
737 BPTR curr = hunks;
738 while (curr)
740 struct hunk *hunk = BPTR2HUNK(BADDR(curr));
742 CacheClearE(hunk->data, hunk->size, CACRF_ClearD | CACRF_ClearI);
744 curr = hunk->next;
748 /* deallocate the symbol tables */
749 for (i = 0; i < int_shnum; i++)
751 if (((sh[i].type == SHT_SYMTAB) || (sh[i].type == SHT_STRTAB)) && (sh[i].addr != NULL))
752 ilsFreeMem(sh[i].addr, sh[i].size);
755 /* Free the section headers */
756 ilsFreeMem(sh, int_shnum * eh.shentsize);
758 return hunks;