diskimage: Compiler delint
[AROS.git] / rom / dos / internalloadseg_elf.c
blob07069b0e316edd8a23dfe86a591e221a53ed1280
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 DATTR(x)
14 #include <aros/asmcall.h>
15 #include <aros/debug.h>
16 #include <aros/macros.h>
17 #include <exec/memory.h>
18 #include <dos/elf.h>
19 #include <dos/dosasl.h>
20 #include <libraries/debug.h>
21 #include <resources/processor.h>
22 #include <proto/dos.h>
23 #include <proto/arossupport.h>
24 #include <proto/debug.h>
25 #include <proto/exec.h>
27 #include <string.h>
28 #include <stddef.h>
30 #include "internalloadseg.h"
31 #include "dos_intern.h"
32 #include "include/loadseg.h"
34 struct hunk
36 ULONG size;
37 BPTR next;
38 char data[0];
39 } __attribute__((packed));
41 #define BPTR2HUNK(bptr) ((struct hunk *)((void *)bptr - offsetof(struct hunk, next)))
42 #define HUNK2BPTR(hunk) MKBADDR(&hunk->next)
44 static int elf_read_block
46 BPTR file,
47 ULONG offset,
48 APTR buffer,
49 ULONG size,
50 SIPTR *funcarray,
51 struct DosLibrary *DOSBase
54 if (ilsSeek(file, offset, OFFSET_BEGINNING) < 0)
55 return 1;
57 return read_block(file, buffer, size, funcarray, DOSBase);
60 static void *load_block
62 BPTR file,
63 ULONG offset,
64 ULONG size,
65 SIPTR *funcarray,
66 struct DosLibrary *DOSBase
69 D(bug("[ELF Loader] Load Block\n"));
70 D(bug("[ELF Loader] (size=%d)\n",size));
71 D(bug("[ELF Loader] (funcarray=0x%x)\n",funcarray));
72 D(bug("[ELF Loader] (funcarray[1]=0x%x)\n",funcarray[1]));
73 void *block = ilsAllocMem(size, MEMF_ANY);
74 if (block)
76 if (!elf_read_block(file, offset, block, size, funcarray, DOSBase))
77 return block;
79 ilsFreeMem(block, size);
81 else
82 SetIoErr(ERROR_NO_FREE_STORE);
84 return NULL;
87 static ULONG read_shnum(BPTR file, struct elfheader *eh, SIPTR *funcarray, struct DosLibrary *DOSBase)
89 ULONG shnum = eh->shnum;
91 /* the ELF header only uses 16 bits to store the count of section headers,
92 * so it can't handle more than 65535 headers. if the count is 0, and an
93 * offset is defined, then the real count can be found in the first
94 * section header (which always exists).
96 * similarly, if the string table index is SHN_XINDEX, then the actual
97 * index is found in the first section header also.
99 * see the System V ABI 2001-04-24 draft for more details.
101 if (eh->shnum == 0)
103 struct sheader sh;
105 if (eh->shoff == 0) {
106 D(bug("[ELF Loader] No section header\n"));
107 SetIoErr(ERROR_NOT_EXECUTABLE);
108 return 0;
111 if (elf_read_block(file, eh->shoff, &sh, sizeof(sh), funcarray, DOSBase))
112 return 0;
114 /* wider section header count is in the size field */
115 shnum = sh.size;
117 /* sanity, if they're still invalid then this isn't elf */
118 if (shnum == 0) {
119 D(bug("[ELF Loader] Empty section header\n"));
120 SetIoErr(ERROR_NOT_EXECUTABLE);
124 return shnum;
127 static int load_header(BPTR file, struct elfheader *eh, SIPTR *funcarray, struct DosLibrary *DOSBase)
129 if (elf_read_block(file, 0, eh, sizeof(struct elfheader), funcarray, DOSBase))
130 return 0;
132 if (eh->ident[0] != 0x7f || eh->ident[1] != 'E' ||
133 eh->ident[2] != 'L' || eh->ident[3] != 'F') {
134 D(bug("[ELF Loader] Not an ELF object\n"));
135 SetIoErr(ERROR_NOT_EXECUTABLE);
136 return 0;
138 D(bug("[ELF Loader] ELF object\n"));
140 /* WANT_CLASS should be defined for your target */
141 if (eh->ident[EI_CLASS] != AROS_ELF_CLASS ||
142 eh->ident[EI_VERSION] != EV_CURRENT ||
143 eh->type != ET_REL ||
144 eh->ident[EI_DATA] != AROS_ELF_DATA ||
145 eh->machine != AROS_ELF_MACHINE)
147 D(bug("[ELF Loader] Object is of wrong type\n"));
148 D(bug("[ELF Loader] EI_CLASS is %d - should be %d\n", eh->ident[EI_CLASS] , AROS_ELF_CLASS ));
149 D(bug("[ELF Loader] EI_VERSION is %d - should be %d\n", eh->ident[EI_VERSION], EV_CURRENT ));
150 D(bug("[ELF Loader] type is %d - should be %d\n", eh->type , ET_REL ));
151 D(bug("[ELF Loader] EI_DATA is %d - should be %d\n", eh->ident[EI_DATA] , AROS_ELF_DATA ));
152 D(bug("[ELF Loader] machine is %d - should be %d\n", eh->machine , AROS_ELF_MACHINE));
154 SetIoErr(ERROR_NOT_EXECUTABLE);
155 return 0;
158 return 1;
161 static int load_hunk
163 BPTR file,
164 BPTR **next_hunk_ptr,
165 struct sheader *sh,
166 CONST_STRPTR strtab,
167 SIPTR *funcarray,
168 BOOL do_align,
169 struct DosLibrary *DOSBase
172 struct hunk *hunk;
173 ULONG hunk_size;
174 ULONG memflags = 0;
176 if (!sh->size)
177 return 1;
179 /* The size of the hunk is the size of the section, plus
180 the size of the hunk structure, plus the size of the alignment (if necessary)*/
181 hunk_size = sh->size + sizeof(struct hunk);
183 if (do_align)
185 hunk_size += sh->addralign;
187 /* Also create space for a trampoline, if necessary */
188 if (sh->flags & SHF_EXECINSTR)
189 hunk_size += sizeof(struct FullJumpVec);
192 if (strtab) {
193 CONST_STRPTR nameext;
195 nameext = strrchr(strtab + sh->name, '.');
196 if (nameext) {
197 if (strcmp(nameext, ".MEMF_CHIP")==0) {
198 memflags |= MEMF_CHIP;
199 } else if (strcmp(nameext, ".MEMF_LOCAL")==0) {
200 memflags |= MEMF_LOCAL;
201 } else if (strcmp(nameext, ".MEMF_KICK")==0) {
202 memflags |= MEMF_KICK;
203 } else if (strcmp(nameext, ".MEMF_FAST")==0) {
204 memflags |= MEMF_FAST;
205 } else if (strcmp(nameext, ".MEMF_PUBLIC")==0) {
206 memflags |= MEMF_PUBLIC;
211 hunk = ilsAllocMem(hunk_size, memflags | MEMF_PUBLIC | (sh->type == SHT_NOBITS ? MEMF_CLEAR : 0));
212 if (hunk)
214 hunk->next = 0;
215 hunk->size = hunk_size;
217 /* In case we are required to honour alignment, and If this section contains
218 executable code, create a trampoline to its beginning, so that even if the
219 alignment requirements make the actual code go much after the end of the
220 hunk structure, the code can still be reached in the usual way. */
221 if (do_align)
223 if (sh->flags & SHF_EXECINSTR)
225 sh->addr = (char *)AROS_ROUNDUP2
227 (IPTR)hunk->data + sizeof(struct FullJumpVec), sh->addralign
229 __AROS_SET_FULLJMP((struct FullJumpVec *)hunk->data, sh->addr);
231 else
232 sh->addr = (char *)AROS_ROUNDUP2((IPTR)hunk->data, sh->addralign);
234 else
235 sh->addr = hunk->data;
237 /* Link the previous one with the new one */
238 BPTR2HUNK(*next_hunk_ptr)->next = HUNK2BPTR(hunk);
240 D(bug("[dos] hunk @ %p, size=%08x, addr @ %p\n", hunk, hunk->size, sh->addr));
242 /* Update the pointer to the previous one, which is now the current one */
243 *next_hunk_ptr = &hunk->next;
245 if (sh->type != SHT_NOBITS)
246 return !elf_read_block(file, sh->offset, sh->addr, sh->size, funcarray, DOSBase);
248 return 1;
252 SetIoErr(ERROR_NO_FREE_STORE);
254 return 0;
257 static int relocate
259 struct elfheader *eh,
260 struct sheader *sh,
261 ULONG shrel_idx,
262 struct sheader *symtab_shndx,
263 struct DosLibrary *DOSBase
266 struct sheader *shrel = &sh[shrel_idx];
267 struct sheader *shsymtab = &sh[SHINDEX(shrel->link)];
268 struct sheader *toreloc = &sh[SHINDEX(shrel->info)];
270 struct symbol *symtab = (struct symbol *)shsymtab->addr;
271 struct relo *rel = (struct relo *)shrel->addr;
274 * Ignore relocs if the target section has no allocation. that can happen
275 * eg. with a .debug PROGBITS and a .rel.debug section
277 if (!(toreloc->flags & SHF_ALLOC))
278 return 1;
280 ULONG numrel = shrel->size / shrel->entsize;
281 ULONG i;
283 for (i=0; i<numrel; i++, rel++)
285 struct symbol *sym;
286 ULONG *p;
287 IPTR s;
288 ULONG shindex;
290 #ifdef __arm__
292 * R_ARM_V4BX are actually special marks for the linker.
293 * They even never have a target (shindex == SHN_UNDEF),
294 * so we simply ignore them before doing any checks.
296 if (ELF_R_TYPE(rel->info) == R_ARM_V4BX)
297 continue;
298 #endif
300 sym = &symtab[ELF_R_SYM(rel->info)];
301 p = toreloc->addr + rel->offset;
303 if (sym->shindex != SHN_XINDEX)
304 shindex = sym->shindex;
306 else {
307 if (symtab_shndx == NULL) {
308 D(bug("[ELF Loader] got symbol with shndx 0xfff, but there's no symtab shndx table\n"));
309 SetIoErr(ERROR_BAD_HUNK);
310 return 0;
312 shindex = ((ULONG *)symtab_shndx->addr)[ELF_R_SYM(rel->info)];
315 DB2(bug("[ELF Loader] Processing symbol %s\n", sh[SHINDEX(shsymtab->link)].addr + sym->name));
317 switch (shindex)
320 case SHN_COMMON:
321 D(bug("[ELF Loader] COMMON symbol '%s'\n",
322 (STRPTR)sh[SHINDEX(shsymtab->link)].addr + sym->name));
323 SetIoErr(ERROR_BAD_HUNK);
325 return 0;
327 case SHN_ABS:
328 s = sym->value;
329 break;
331 case SHN_UNDEF:
332 if (ELF_R_TYPE(rel->info) != 0) {
333 D(bug("[ELF Loader] Undefined symbol '%s'\n",
334 (STRPTR)sh[SHINDEX(shsymtab->link)].addr + sym->name));
335 SetIoErr(ERROR_BAD_HUNK);
336 return 0;
338 /* fall through */
340 default:
341 s = (IPTR)sh[SHINDEX(shindex)].addr + sym->value;
344 switch (ELF_R_TYPE(rel->info))
346 #if defined(__i386__)
348 case R_386_32: /* 32bit absolute */
349 *p += s;
350 break;
352 case R_386_PC32: /* 32bit PC relative */
353 *p += s - (ULONG)p;
354 break;
356 case R_386_NONE:
357 break;
359 #elif defined(__x86_64__)
360 case R_X86_64_64: /* 64bit direct/absolute */
361 *(UQUAD *)p = s + rel->addend;
362 break;
364 case R_X86_64_PC32: /* PC relative 32 bit signed */
365 *(ULONG *)p = s + rel->addend - (IPTR) p;
366 break;
368 case R_X86_64_32:
369 *(ULONG *)p = (UQUAD)s + (UQUAD)rel->addend;
370 break;
372 case R_X86_64_32S:
373 *(LONG *)p = (QUAD)s + (QUAD)rel->addend;
374 break;
376 case R_X86_64_NONE: /* No reloc */
377 break;
379 #elif defined(__mc68000__)
381 case R_68K_32:
382 *p = s + rel->addend;
383 break;
385 case R_68K_16:
386 *(UWORD *)p = s + rel->addend;
387 break;
389 case R_68K_8:
390 *(UBYTE *)p = s + rel->addend;
391 break;
393 case R_68K_PC32:
394 *p = s + rel->addend - (ULONG)p;
395 break;
397 case R_68K_PC16:
398 *(UWORD *)p = s + rel->addend - (ULONG)p;
399 break;
401 case R_68K_PC8:
402 *(UBYTE *)p = s + rel->addend - (ULONG)p;
403 break;
405 case R_68K_NONE:
406 break;
408 #elif defined(__ppc__) || defined(__powerpc__)
410 case R_PPC_ADDR32:
411 *p = s + rel->addend;
412 break;
414 case R_PPC_ADDR16_LO:
416 unsigned short *c = (unsigned short *) p;
417 *c = (s + rel->addend) & 0xffff;
419 break;
421 case R_PPC_ADDR16_HA:
423 unsigned short *c = (unsigned short *) p;
424 ULONG temp = s + rel->addend;
425 *c = temp >> 16;
426 if ((temp & 0x8000) != 0)
427 (*c)++;
429 break;
431 case R_PPC_REL16_LO:
433 unsigned short *c = (unsigned short *) p;
434 *c = (s + rel->addend - (ULONG) p) & 0xffff;
436 break;
438 case R_PPC_REL16_HA:
440 unsigned short *c = (unsigned short *) p;
441 ULONG temp = s + rel->addend - (ULONG) p;
442 *c = temp >> 16;
443 if ((temp & 0x8000) != 0)
444 (*c)++;
446 break;
448 case R_PPC_REL24:
449 *p &= ~0x3fffffc;
450 *p |= (s + rel->addend - (ULONG) p) & 0x3fffffc;
451 break;
453 case R_PPC_REL32:
454 *p = s + rel->addend - (ULONG) p;
455 break;
457 case R_PPC_NONE:
458 break;
460 #elif defined(__arm__)
461 case R_ARM_CALL:
462 case R_ARM_JUMP24:
463 case R_ARM_PC24:
464 case R_ARM_PREL31:
466 /* On ARM the 24 bit offset is shifted by 2 to the right */
467 signed long offset = (*p & 0x00ffffff) << 2;
468 /* If highest bit set, make offset negative */
469 if (offset & 0x02000000)
470 offset -= 0x04000000;
472 if (offset >= 0x02000000 ||
473 offset <= -0x02000000)
475 bug("[ELF Loader] Relocation type %d %d out of range!\n", i, ELF_R_TYPE(rel->info));
476 SetIoErr(ERROR_BAD_HUNK);
477 return 0;
479 offset += s - (ULONG)p;
481 offset >>= 2;
482 *p &= 0xff000000;
483 *p |= offset & 0x00ffffff;
485 break;
487 case R_ARM_THM_CALL:
488 case R_ARM_THM_JUMP24:
490 ULONG upper,lower,sign,j1,j2;
491 LONG offset;
493 upper = *((UWORD *)p);
494 lower = *((UWORD *)p+1);
496 sign = (upper >> 10) & 1;
497 j1 = (lower >> 13) & 1;
498 j2 = (lower >> 11) & 1;
500 offset = (sign << 24) | ((~(j1 ^ sign) & 1) << 23) |
501 ((~(j2 ^ sign) & 1) << 22) |
502 ((upper & 0x03ff) << 12) |
503 ((lower & 0x07ff) << 1);
505 if (offset & 0x01000000)
506 offset -= 0x02000000;
508 if (offset >= 0x01000000 ||
509 offset <= -0x01000000)
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 sign = (offset >> 24) & 1;
518 j1 = sign ^ (~(offset >> 23) & 1);
519 j2 = sign ^ (~(offset >> 22) & 1);
521 *(UWORD *)p = (UWORD)((upper & 0xf800) | (sign << 10) |
522 ((offset >> 12) & 0x03ff));
523 *((UWORD *)p + 1) = (UWORD)((lower & 0xd000) |
524 (j1 << 13) | (j2 << 11) | ((offset >> 1) & 0x07ff));
527 break;
529 case R_ARM_THM_MOVW_ABS_NC:
530 case R_ARM_THM_MOVT_ABS:
532 ULONG upper,lower;
533 LONG offset;
535 upper = *((UWORD *)p);
536 lower = *((UWORD *)p+1);
538 offset = ((upper & 0x000f) << 12) |
539 ((upper & 0x0400) << 1) |
540 ((lower & 0x7000) >> 4) |
541 (lower & 0x00ff);
543 offset = (offset ^ 0x8000) - 0x8000;
545 offset += s;
547 if (ELF_R_TYPE(rel->info) == R_ARM_THM_MOVT_ABS)
548 offset >>= 16;
550 *(UWORD *)p = (UWORD)((upper & 0xfbf0) |
551 ((offset & 0xf000) >> 12) |
552 ((offset & 0x0800) >> 1));
553 *((UWORD *)p + 1) = (UWORD)((lower & 0x8f00) |
554 ((offset & 0x0700)<< 4) |
555 (offset & 0x00ff));
557 break;
559 case R_ARM_MOVW_ABS_NC:
560 case R_ARM_MOVT_ABS:
562 signed long offset = *p;
563 offset = ((offset & 0xf0000) >> 4) | (offset & 0xfff);
564 offset = (offset ^ 0x8000) - 0x8000;
566 offset += s;
568 if (ELF_R_TYPE(rel->info) == R_ARM_MOVT_ABS)
569 offset >>= 16;
571 *p &= 0xfff0f000;
572 *p |= ((offset & 0xf000) << 4) | (offset & 0x0fff);
574 break;
576 case R_ARM_ABS32:
577 *p += s;
578 break;
580 case R_ARM_NONE:
581 break;
583 #else
584 # error Your architecture is not supported
585 #endif
587 default:
588 D(bug("[ELF Loader] Unrecognized relocation type %d %d\n", i, ELF_R_TYPE(rel->info)));
589 SetIoErr(ERROR_BAD_HUNK);
590 return 0;
594 return 1;
597 #ifdef __arm__
600 * On ARM < v6 all LONG accesses must be LONG-aligned
601 * TODO: This is useful and can be moved to some public include file.
603 #if (__ARM_ARCH__ > 5)
605 #define READLONG_UNALIGNED(src) src
607 #else
609 static inline ULONG readlong_unaligned(ULONG *src)
611 ULONG res, tmp;
613 asm volatile(
614 "ldrb %0, [%2, #0]\n\t"
615 "ldrb %1, [%2, #1]\n\t"
616 "orr %0, %0, %1, lsl #8\n\t"
617 "ldrb %1, [%2, #2]\n\t"
618 "orr %0, %0, %1, lsl #16\n\t"
619 "ldrb %1, [%2, #3]\n\t"
620 "orr %0, %0, %1, lsl #24"
621 :"=&r"(res), "=&r"(tmp) : "r"(src)
624 return res;
627 #define READLONG_UNALIGNED(src) readlong_unaligned(&src);
628 #endif
631 * This code parses special .ARM.Attributes section and
632 * extracts system requirements from it. Things like float ABI,
633 * minimum CPU and FPU version are described there.
636 static UBYTE arm_cpus[] =
638 CPUFAMILY_ARM_3,
639 CPUFAMILY_ARM_4,
640 CPUFAMILY_ARM_4T,
641 CPUFAMILY_ARM_5T,
642 CPUFAMILY_ARM_5TE,
643 CPUFAMILY_ARM_5TEJ,
644 CPUFAMILY_ARM_6,
645 CPUFAMILY_ARM_6,
646 CPUFAMILY_ARM_6, /* 6KZ */
647 CPUFAMILY_ARM_6, /* 6T2 */
648 CPUFAMILY_ARM_6, /* 6K */
649 CPUFAMILY_ARM_7,
650 CPUFAMILY_ARM_6, /* 6-M */
651 CPUFAMILY_ARM_6, /* 6S-M */
652 CPUFAMILY_ARM_7 /* 7E-M */
655 static BOOL ARM_ParseAttrs(UBYTE *data, ULONG len, struct DosLibrary *DOSBase)
657 struct attrs_section *attrs;
659 if (data[0] != ATTR_VERSION_CURRENT)
661 DATTR(bug("[ELF.ARM] Unknown attributes version: 0x%02\n", data[0]));
662 return FALSE;
665 attrs = (void *)data + 1;
666 while (len > 0)
668 ULONG attrs_size = READLONG_UNALIGNED(attrs->size);
670 if (!strcmp(attrs->vendor, "aeabi"))
672 struct attrs_subsection *aeabi_attrs = (void *)attrs->vendor + 6;
673 ULONG aeabi_len = attrs_size - 10;
675 DATTR(bug("[ELF.ARM] Found aeabi attributes @ 0x%p (length %u)\n", aeabi_attrs, aeabi_len));
677 while (aeabi_len > 0)
679 ULONG aeabi_attrs_size = READLONG_UNALIGNED(aeabi_attrs->size);
681 if (aeabi_attrs->tag == Tag_File)
683 UBYTE *file_subsection = (void *)aeabi_attrs + sizeof(struct attrs_subsection);
684 UBYTE file_len = aeabi_attrs_size - sizeof(struct attrs_subsection);
686 DATTR(bug("[ELF.ARM] Found file-wide attributes @ 0x%p (length %u)\n", file_subsection, file_len));
688 while (file_len > 0)
690 UBYTE tag, shift;
691 ULONG val = 0;
693 tag = *file_subsection++;
694 file_len--;
696 if (file_len == 0)
698 DATTR(bug("[ELF.ARM] Mailformed attribute tag %d (no data)\n", tag));
699 return FALSE;
702 switch (tag)
704 case Tag_CPU_raw_name:
705 case Tag_CPU_name:
706 case Tag_compatibility:
707 case Tag_also_compatible_with:
708 case Tag_conformance:
709 /* These two are NULL-terminated strings. Just skip. */
710 while (file_len)
712 file_len--;
713 if (*file_subsection++ == 0)
714 break;
716 break;
718 default:
719 /* Read ULEB128 value */
720 shift = 0;
721 while (file_len)
723 UBYTE byte;
725 byte = *file_subsection++;
726 file_len--;
728 val |= (byte & 0x7F) << shift;
729 if (!(byte & 0x80))
730 break;
732 shift += 7;
736 switch (tag)
738 case Tag_CPU_arch:
739 DATTR(bug("[ELF.ARM] ARM CPU architecture set to %d\n", val));
741 if (val > ELF_CPU_ARMv7EM)
743 DATTR(bug("[ELF.ARM] Unknown CPU tag value (%d)\n", val));
744 return FALSE;
747 if (arm_cpus[val] > IDosBase(DOSBase)->arm_Arch)
749 DATTR(bug("[ELF.ARM] CPU Requirements too high (system %d, file %d)\n", IDosBase(DOSBase)->arm_Arch, arm_cpus[val]));
750 return FALSE;
752 break;
754 case Tag_FP_arch:
755 DATTR(bug("[ELF.ARM] ARM FPU architecture set to %d\n", val));
757 switch (val)
759 case ELF_FP_None:
760 break;
762 case ELF_FP_v1:
763 case ELF_FP_v2:
764 if (!IDosBase(DOSBase)->arm_VFP)
766 DATTR(bug("[ELF.ARM] VFP required but missing\n"));
767 return FALSE;
769 break;
771 case ELF_FP_v3:
772 case ELF_FP_v3_Short:
773 if (!IDosBase(DOSBase)->arm_VFP_v3)
775 DATTR(bug("[ELF.ARM] VFPv3 required but missing\n"));
776 return FALSE;
778 break;
780 default:
781 /* This includes VFPv4 for now */
782 DATTR(bug("[ELF.ARM] VFP %d required -- unsupported\n", val));
783 return FALSE;
786 break;
790 /* We allow to execute only files which contain attributes section */
791 return TRUE;
793 aeabi_attrs = (void *)aeabi_attrs + aeabi_attrs_size;
794 aeabi_len -= aeabi_attrs_size;
797 return FALSE;
799 attrs = (void *)attrs + attrs_size;
800 len -= attrs_size;
802 return FALSE;
805 #endif
807 BPTR InternalLoadSeg_ELF
809 BPTR file,
810 BPTR table __unused,
811 SIPTR *funcarray,
812 LONG *stack __unused,
813 struct DosLibrary *DOSBase
816 struct elfheader eh;
817 struct sheader *sh;
818 struct sheader *symtab_shndx = NULL;
819 struct sheader *strtab = NULL;
820 BPTR hunks = 0;
821 BPTR *next_hunk_ptr = &hunks;
822 ULONG i;
823 BOOL exec_hunk_seen = FALSE;
824 ULONG int_shnum;
826 /* load and validate ELF header */
827 if (!load_header(file, &eh, funcarray, DOSBase))
828 return 0;
830 int_shnum = read_shnum(file, &eh, funcarray, DOSBase);
831 if (!int_shnum)
832 return 0;
834 /* load section headers */
835 if (!(sh = load_block(file, eh.shoff, int_shnum * eh.shentsize, funcarray, DOSBase)))
836 return 0;
838 #ifdef __arm__
839 for (i = 0; i < int_shnum; i++)
841 if (sh[i].type == SHT_ARM_ATTRIBUTES)
843 ULONG len = sh[i].size;
844 UBYTE *data = load_block(file, sh[i].offset, len, funcarray, DOSBase);
846 if (data)
848 BOOL res = ARM_ParseAttrs(data, len, DOSBase);
850 ilsFreeMem(data, len);
852 if (!res)
854 D(bug("[ELF Loader] Can't parse ARM attributes\n"));
855 SetIoErr(ERROR_NOT_EXECUTABLE);
856 goto error;
861 #endif
863 /* Iterate over the section headers in order to do some stuff... */
864 for (i = 0; i < int_shnum; i++)
867 Load the symbol and string table(s).
869 NOTICE: the ELF standard, at the moment (Nov 2002) explicitely states
870 that only one symbol table per file is allowed. However, it
871 also states that this may change in future... we already handle it.
873 if (sh[i].type == SHT_SYMTAB || sh[i].type == SHT_STRTAB || sh[i].type == SHT_SYMTAB_SHNDX)
875 sh[i].addr = load_block(file, sh[i].offset, sh[i].size, funcarray, DOSBase);
876 if (!sh[i].addr)
877 goto error;
879 if (sh[i].type == SHT_STRTAB) {
880 if (strtab == NULL) {
881 strtab = &sh[i];
882 } else {
883 D(bug("[ELF Loader] file contains multiple strtab tables. only using the first one\n"));
887 if (sh[i].type == SHT_SYMTAB_SHNDX) {
888 if (symtab_shndx == NULL)
889 symtab_shndx = &sh[i];
890 else
891 D(bug("[ELF Loader] file contains multiple symtab shndx tables. only using the first one\n"));
896 /* Now that we have the string and symbol tables loaded,
897 * load the rest of the hunks.
899 for (i = 0; i < int_shnum; i++)
901 /* Skip the already loaded hunks */
902 if (sh[i].type == SHT_SYMTAB || sh[i].type == SHT_STRTAB || sh[i].type == SHT_SYMTAB_SHNDX)
903 continue;
905 /* Load the section in memory if needed, and make a hunk out of it */
906 if (sh[i].flags & SHF_ALLOC)
908 if (sh[i].size)
910 /* Only allow alignment if this is an executable hunk
911 or if an executable hunk has been loaded already,
912 so to avoid the situation in which a data hunk has its
913 content displaced from the hunk's header in case it's the
914 first hunk (this happens with Keymaps, for instance). */
915 if (sh[i].flags & SHF_EXECINSTR)
916 exec_hunk_seen = TRUE;
918 if (!load_hunk(file, &next_hunk_ptr, &sh[i], strtab ? strtab->addr : NULL, funcarray, exec_hunk_seen, DOSBase))
919 goto error;
924 /* Relocate the sections */
925 for (i = 0; i < int_shnum; i++)
927 /* Does this relocation section refer to a hunk? If so, addr must be != 0 */
928 if ((sh[i].type == AROS_ELF_REL) && sh[SHINDEX(sh[i].info)].addr)
930 sh[i].addr = load_block(file, sh[i].offset, sh[i].size, funcarray, DOSBase);
931 if (!sh[i].addr || !relocate(&eh, sh, i, symtab_shndx, DOSBase))
932 goto error;
934 ilsFreeMem(sh[i].addr, sh[i].size);
935 sh[i].addr = NULL;
939 /* Everything is loaded now. Register the module at kernel.resource */
940 register_elf(file, hunks, &eh, sh, DOSBase);
941 goto end;
943 error:
945 /* There were some errors, deallocate The hunks */
947 InternalUnLoadSeg(hunks, (VOID_FUNC)funcarray[2]);
948 hunks = 0;
950 end:
953 * Clear the caches to let the CPU see the new data and instructions.
954 * We check for SysBase's lib_Version, since this code is also built
955 * as linklib for AmigaOS version of AROS bootstrap, and it can be
956 * running on AOS 1.3 or lower.
958 if (SysBase->LibNode.lib_Version >= 36)
960 BPTR curr = hunks;
962 while (curr)
964 struct hunk *hunk = BPTR2HUNK(BADDR(curr));
966 CacheClearE(hunk->data, hunk->size, CACRF_ClearD | CACRF_ClearI);
968 curr = hunk->next;
972 /* deallocate the symbol tables */
973 for (i = 0; i < int_shnum; i++)
975 if (((sh[i].type == SHT_SYMTAB) || (sh[i].type == SHT_STRTAB)) && (sh[i].addr != NULL))
976 ilsFreeMem(sh[i].addr, sh[i].size);
979 /* Free the section headers */
980 ilsFreeMem(sh, int_shnum * eh.shentsize);
982 return hunks;