Call CloseDevice() before DeleteIORequest(), and don't call
[AROS.git] / rom / dos / internalloadseg_elf.c
blob848d8be48512ffc0c699edfb5bbe143e324cd67d
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 SetIoErr(ERROR_NOT_EXECUTABLE);
107 return 0;
110 if (elf_read_block(file, eh->shoff, &sh, sizeof(sh), funcarray, DOSBase))
111 return 0;
113 /* wider section header count is in the size field */
114 shnum = sh.size;
116 /* sanity, if they're still invalid then this isn't elf */
117 if (shnum == 0)
118 SetIoErr(ERROR_NOT_EXECUTABLE);
121 return shnum;
124 static int load_header(BPTR file, struct elfheader *eh, SIPTR *funcarray, struct DosLibrary *DOSBase)
126 if (elf_read_block(file, 0, eh, sizeof(struct elfheader), funcarray, DOSBase))
127 return 0;
129 if (eh->ident[0] != 0x7f || eh->ident[1] != 'E' ||
130 eh->ident[2] != 'L' || eh->ident[3] != 'F') {
131 D(bug("[ELF Loader] Not an ELF object\n"));
132 SetIoErr(ERROR_NOT_EXECUTABLE);
133 return 0;
135 D(bug("[ELF Loader] ELF object\n"));
137 /* WANT_CLASS should be defined for your target */
138 if (eh->ident[EI_CLASS] != AROS_ELF_CLASS ||
139 eh->ident[EI_VERSION] != EV_CURRENT ||
140 eh->type != ET_REL ||
141 eh->ident[EI_DATA] != AROS_ELF_DATA ||
142 eh->machine != AROS_ELF_MACHINE)
144 D(bug("[ELF Loader] Object is of wrong type\n"));
145 D(bug("[ELF Loader] EI_CLASS is %d - should be %d\n", eh->ident[EI_CLASS] , AROS_ELF_CLASS ));
146 D(bug("[ELF Loader] EI_VERSION is %d - should be %d\n", eh->ident[EI_VERSION], EV_CURRENT ));
147 D(bug("[ELF Loader] type is %d - should be %d\n", eh->type , ET_REL ));
148 D(bug("[ELF Loader] EI_DATA is %d - should be %d\n", eh->ident[EI_DATA] , AROS_ELF_DATA ));
149 D(bug("[ELF Loader] machine is %d - should be %d\n", eh->machine , AROS_ELF_MACHINE));
151 SetIoErr(ERROR_NOT_EXECUTABLE);
152 return 0;
155 return 1;
158 static int load_hunk
160 BPTR file,
161 BPTR **next_hunk_ptr,
162 struct sheader *sh,
163 CONST_STRPTR strtab,
164 SIPTR *funcarray,
165 BOOL do_align,
166 struct DosLibrary *DOSBase
169 struct hunk *hunk;
170 ULONG hunk_size;
171 ULONG memflags = 0;
173 if (!sh->size)
174 return 1;
176 /* The size of the hunk is the size of the section, plus
177 the size of the hunk structure, plus the size of the alignment (if necessary)*/
178 hunk_size = sh->size + sizeof(struct hunk);
180 if (do_align)
182 hunk_size += sh->addralign;
184 /* Also create space for a trampoline, if necessary */
185 if (sh->flags & SHF_EXECINSTR)
186 hunk_size += sizeof(struct FullJumpVec);
189 if (strtab) {
190 CONST_STRPTR nameext;
192 nameext = strrchr(strtab + sh->name, '.');
193 if (nameext) {
194 if (strcmp(nameext, ".MEMF_CHIP")==0) {
195 memflags |= MEMF_CHIP;
196 } else if (strcmp(nameext, ".MEMF_LOCAL")==0) {
197 memflags |= MEMF_LOCAL;
198 } else if (strcmp(nameext, ".MEMF_KICK")==0) {
199 memflags |= MEMF_KICK;
200 } else if (strcmp(nameext, ".MEMF_FAST")==0) {
201 memflags |= MEMF_FAST;
202 } else if (strcmp(nameext, ".MEMF_PUBLIC")==0) {
203 memflags |= MEMF_PUBLIC;
208 hunk = ilsAllocMem(hunk_size, memflags | MEMF_PUBLIC | (sh->type == SHT_NOBITS ? MEMF_CLEAR : 0));
209 if (hunk)
211 hunk->next = 0;
212 hunk->size = hunk_size;
214 /* In case we are required to honour alignment, and If this section contains
215 executable code, create a trampoline to its beginning, so that even if the
216 alignment requirements make the actual code go much after the end of the
217 hunk structure, the code can still be reached in the usual way. */
218 if (do_align)
220 if (sh->flags & SHF_EXECINSTR)
222 sh->addr = (char *)AROS_ROUNDUP2
224 (IPTR)hunk->data + sizeof(struct FullJumpVec), sh->addralign
226 __AROS_SET_FULLJMP((struct FullJumpVec *)hunk->data, sh->addr);
228 else
229 sh->addr = (char *)AROS_ROUNDUP2((IPTR)hunk->data, sh->addralign);
231 else
232 sh->addr = hunk->data;
234 /* Link the previous one with the new one */
235 BPTR2HUNK(*next_hunk_ptr)->next = HUNK2BPTR(hunk);
237 D(bug("[dos] hunk @ %p, size=%08x, addr @ %p\n", hunk, hunk->size, sh->addr));
239 /* Update the pointer to the previous one, which is now the current one */
240 *next_hunk_ptr = &hunk->next;
242 if (sh->type != SHT_NOBITS)
243 return !elf_read_block(file, sh->offset, sh->addr, sh->size, funcarray, DOSBase);
245 return 1;
249 SetIoErr(ERROR_NO_FREE_STORE);
251 return 0;
254 static int relocate
256 struct elfheader *eh,
257 struct sheader *sh,
258 ULONG shrel_idx,
259 struct sheader *symtab_shndx,
260 struct DosLibrary *DOSBase
263 struct sheader *shrel = &sh[shrel_idx];
264 struct sheader *shsymtab = &sh[SHINDEX(shrel->link)];
265 struct sheader *toreloc = &sh[SHINDEX(shrel->info)];
267 struct symbol *symtab = (struct symbol *)shsymtab->addr;
268 struct relo *rel = (struct relo *)shrel->addr;
271 * Ignore relocs if the target section has no allocation. that can happen
272 * eg. with a .debug PROGBITS and a .rel.debug section
274 if (!(toreloc->flags & SHF_ALLOC))
275 return 1;
277 ULONG numrel = shrel->size / shrel->entsize;
278 ULONG i;
280 #ifndef NO_SYSBASE_REMAP
281 struct symbol *SysBase_sym = NULL;
282 #endif
284 for (i=0; i<numrel; i++, rel++)
286 struct symbol *sym;
287 ULONG *p;
288 IPTR s;
289 ULONG shindex;
291 #ifdef __arm__
293 * R_ARM_V4BX are actually special marks for the linker.
294 * They even never have a target (shindex == SHN_UNDEF),
295 * so we simply ignore them before doing any checks.
297 if (ELF_R_TYPE(rel->info) == R_ARM_V4BX)
298 continue;
299 #endif
301 sym = &symtab[ELF_R_SYM(rel->info)];
302 p = toreloc->addr + rel->offset;
304 if (sym->shindex != SHN_XINDEX)
305 shindex = sym->shindex;
307 else {
308 if (symtab_shndx == NULL) {
309 D(bug("[ELF Loader] got symbol with shndx 0xfff, but there's no symtab shndx table\n"));
310 SetIoErr(ERROR_BAD_HUNK);
311 return 0;
313 shindex = ((ULONG *)symtab_shndx->addr)[ELF_R_SYM(rel->info)];
316 DB2(bug("[ELF Loader] Processing symbol %s\n", sh[SHINDEX(shsymtab->link)].addr + sym->name));
318 switch (shindex)
321 case SHN_COMMON:
322 D(bug("[ELF Loader] COMMON symbol '%s'\n",
323 (STRPTR)sh[SHINDEX(shsymtab->link)].addr + sym->name));
324 SetIoErr(ERROR_BAD_HUNK);
326 return 0;
328 case SHN_ABS:
329 #ifdef NO_SYSBASE_REMAP
330 s = sym->value;
331 #else
332 if (SysBase_sym == NULL)
334 if (strncmp((STRPTR)sh[SHINDEX(shsymtab->link)].addr + sym->name, "SysBase", 8) == 0)
336 SysBase_sym = sym;
337 goto SysBase_yes;
339 else
340 goto SysBase_no;
342 else
343 if (SysBase_sym == sym)
345 SysBase_yes: s = (IPTR)&SysBase;
347 else
348 SysBase_no: s = sym->value;
349 #endif
350 break;
352 case SHN_UNDEF:
353 if (ELF_R_TYPE(rel->info) != 0) {
354 D(bug("[ELF Loader] Undefined symbol '%s'\n",
355 (STRPTR)sh[SHINDEX(shsymtab->link)].addr + sym->name));
356 SetIoErr(ERROR_BAD_HUNK);
357 return 0;
359 /* fall through */
361 default:
362 s = (IPTR)sh[SHINDEX(shindex)].addr + sym->value;
365 switch (ELF_R_TYPE(rel->info))
367 #if defined(__i386__)
369 case R_386_32: /* 32bit absolute */
370 *p += s;
371 break;
373 case R_386_PC32: /* 32bit PC relative */
374 *p += s - (ULONG)p;
375 break;
377 case R_386_NONE:
378 break;
380 #elif defined(__x86_64__)
381 case R_X86_64_64: /* 64bit direct/absolute */
382 *(UQUAD *)p = s + rel->addend;
383 break;
385 case R_X86_64_PC32: /* PC relative 32 bit signed */
386 *(ULONG *)p = s + rel->addend - (IPTR) p;
387 break;
389 case R_X86_64_32:
390 *(ULONG *)p = (UQUAD)s + (UQUAD)rel->addend;
391 break;
393 case R_X86_64_32S:
394 *(LONG *)p = (QUAD)s + (QUAD)rel->addend;
395 break;
397 case R_X86_64_NONE: /* No reloc */
398 break;
400 #elif defined(__mc68000__)
402 case R_68K_32:
403 *p = s + rel->addend;
404 break;
406 case R_68K_16:
407 *(UWORD *)p = s + rel->addend;
408 break;
410 case R_68K_8:
411 *(UBYTE *)p = s + rel->addend;
412 break;
414 case R_68K_PC32:
415 *p = s + rel->addend - (ULONG)p;
416 break;
418 case R_68K_PC16:
419 *(UWORD *)p = s + rel->addend - (ULONG)p;
420 break;
422 case R_68K_PC8:
423 *(UBYTE *)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:
485 case R_ARM_PREL31:
487 /* On ARM the 24 bit offset is shifted by 2 to the right */
488 signed long offset = (*p & 0x00ffffff) << 2;
489 /* If highest bit set, make offset negative */
490 if (offset & 0x02000000)
491 offset -= 0x04000000;
493 if (offset >= 0x02000000 ||
494 offset <= -0x02000000)
496 bug("[ELF Loader] Relocation type %d %d out of range!\n", i, ELF_R_TYPE(rel->info));
497 SetIoErr(ERROR_BAD_HUNK);
498 return 0;
500 offset += s - (ULONG)p;
502 offset >>= 2;
503 *p &= 0xff000000;
504 *p |= offset & 0x00ffffff;
506 break;
508 case R_ARM_THM_CALL:
509 case R_ARM_THM_JUMP24:
511 ULONG upper,lower,sign,j1,j2;
512 LONG offset;
514 upper = *((UWORD *)p);
515 lower = *((UWORD *)p+1);
517 sign = (upper >> 10) & 1;
518 j1 = (lower >> 13) & 1;
519 j2 = (lower >> 11) & 1;
521 offset = (sign << 24) | ((~(j1 ^ sign) & 1) << 23) |
522 ((~(j2 ^ sign) & 1) << 22) |
523 ((upper & 0x03ff) << 12) |
524 ((lower & 0x07ff) << 1);
526 if (offset & 0x01000000)
527 offset -= 0x02000000;
529 if (offset >= 0x01000000 ||
530 offset <= -0x01000000)
532 bug("[ELF Loader] Relocation type %d %d out of range!\n", i, ELF_R_TYPE(rel->info));
533 SetIoErr(ERROR_BAD_HUNK);
534 return 0;
536 offset += s - (ULONG)p;
538 sign = (offset >> 24) & 1;
539 j1 = sign ^ (~(offset >> 23) & 1);
540 j2 = sign ^ (~(offset >> 22) & 1);
542 *(UWORD *)p = (UWORD)((upper & 0xf800) | (sign << 10) |
543 ((offset >> 12) & 0x03ff));
544 *((UWORD *)p + 1) = (UWORD)((lower & 0xd000) |
545 (j1 << 13) | (j2 << 11) | ((offset >> 1) & 0x07ff));
548 break;
550 case R_ARM_THM_MOVW_ABS_NC:
551 case R_ARM_THM_MOVT_ABS:
553 ULONG upper,lower;
554 LONG offset;
556 upper = *((UWORD *)p);
557 lower = *((UWORD *)p+1);
559 offset = ((upper & 0x000f) << 12) |
560 ((upper & 0x0400) << 1) |
561 ((lower & 0x7000) >> 4) |
562 (lower & 0x00ff);
564 offset = (offset ^ 0x8000) - 0x8000;
566 offset += s;
568 if (ELF_R_TYPE(rel->info) == R_ARM_THM_MOVT_ABS)
569 offset >>= 16;
571 *(UWORD *)p = (UWORD)((upper & 0xfbf0) |
572 ((offset & 0xf000) >> 12) |
573 ((offset & 0x0800) >> 1));
574 *((UWORD *)p + 1) = (UWORD)((lower & 0x8f00) |
575 ((offset & 0x0700)<< 4) |
576 (offset & 0x00ff));
578 break;
580 case R_ARM_MOVW_ABS_NC:
581 case R_ARM_MOVT_ABS:
583 signed long offset = *p;
584 offset = ((offset & 0xf0000) >> 4) | (offset & 0xfff);
585 offset = (offset ^ 0x8000) - 0x8000;
587 offset += s;
589 if (ELF_R_TYPE(rel->info) == R_ARM_MOVT_ABS)
590 offset >>= 16;
592 *p &= 0xfff0f000;
593 *p |= ((offset & 0xf000) << 4) | (offset & 0x0fff);
595 break;
597 case R_ARM_ABS32:
598 *p += s;
599 break;
601 case R_ARM_NONE:
602 break;
604 #else
605 # error Your architecture is not supported
606 #endif
608 default:
609 D(bug("[ELF Loader] Unrecognized relocation type %d %d\n", i, ELF_R_TYPE(rel->info)));
610 SetIoErr(ERROR_BAD_HUNK);
611 return 0;
615 return 1;
618 #ifdef __arm__
621 * On ARM < v6 all LONG accesses must be LONG-aligned
622 * TODO: This is useful and can be moved to some public include file.
624 #if (__ARM_ARCH__ > 5)
626 #define READLONG_UNALIGNED(src) src
628 #else
630 static inline ULONG readlong_unaligned(ULONG *src)
632 ULONG res, tmp;
634 asm volatile(
635 "ldrb %0, [%2, #0]\n\t"
636 "ldrb %1, [%2, #1]\n\t"
637 "orr %0, %0, %1, lsl #8\n\t"
638 "ldrb %1, [%2, #2]\n\t"
639 "orr %0, %0, %1, lsl #16\n\t"
640 "ldrb %1, [%2, #3]\n\t"
641 "orr %0, %0, %1, lsl #24"
642 :"=&r"(res), "=&r"(tmp) : "r"(src)
645 return res;
648 #define READLONG_UNALIGNED(src) readlong_unaligned(&src);
649 #endif
652 * This code parses special .ARM.Attributes section and
653 * extracts system requirements from it. Things like float ABI,
654 * minimum CPU and FPU version are described there.
657 static UBYTE arm_cpus[] =
659 CPUFAMILY_ARM_3,
660 CPUFAMILY_ARM_4,
661 CPUFAMILY_ARM_4T,
662 CPUFAMILY_ARM_5T,
663 CPUFAMILY_ARM_5TE,
664 CPUFAMILY_ARM_5TEJ,
665 CPUFAMILY_ARM_6,
666 CPUFAMILY_ARM_6,
667 CPUFAMILY_ARM_6, /* 6KZ */
668 CPUFAMILY_ARM_6, /* 6T2 */
669 CPUFAMILY_ARM_6, /* 6K */
670 CPUFAMILY_ARM_7,
671 CPUFAMILY_ARM_6, /* 6-M */
672 CPUFAMILY_ARM_6, /* 6S-M */
673 CPUFAMILY_ARM_7 /* 7E-M */
676 static BOOL ARM_ParseAttrs(UBYTE *data, ULONG len, struct DosLibrary *DOSBase)
678 struct attrs_section *attrs;
680 if (data[0] != ATTR_VERSION_CURRENT)
682 DATTR(bug("[ELF.ARM] Unknown attributes version: 0x%02\n", data[0]));
683 return FALSE;
686 attrs = (void *)data + 1;
687 while (len > 0)
689 ULONG attrs_size = READLONG_UNALIGNED(attrs->size);
691 if (!strcmp(attrs->vendor, "aeabi"))
693 struct attrs_subsection *aeabi_attrs = (void *)attrs->vendor + 6;
694 ULONG aeabi_len = attrs_size - 10;
696 DATTR(bug("[ELF.ARM] Found aeabi attributes @ 0x%p (length %u)\n", aeabi_attrs, aeabi_len));
698 while (aeabi_len > 0)
700 ULONG aeabi_attrs_size = READLONG_UNALIGNED(aeabi_attrs->size);
702 if (aeabi_attrs->tag == Tag_File)
704 UBYTE *file_subsection = (void *)aeabi_attrs + sizeof(struct attrs_subsection);
705 UBYTE file_len = aeabi_attrs_size - sizeof(struct attrs_subsection);
707 DATTR(bug("[ELF.ARM] Found file-wide attributes @ 0x%p (length %u)\n", file_subsection, file_len));
709 while (file_len > 0)
711 UBYTE tag, shift;
712 ULONG val = 0;
714 tag = *file_subsection++;
715 file_len--;
717 if (file_len == 0)
719 DATTR(bug("[ELF.ARM] Mailformed attribute tag %d (no data)\n", tag));
720 return FALSE;
723 switch (tag)
725 case Tag_CPU_raw_name:
726 case Tag_CPU_name:
727 case Tag_compatibility:
728 case Tag_also_compatible_with:
729 case Tag_conformance:
730 /* These two are NULL-terminated strings. Just skip. */
731 while (file_len)
733 file_len--;
734 if (*file_subsection++ == 0)
735 break;
737 break;
739 default:
740 /* Read ULEB128 value */
741 shift = 0;
742 while (file_len)
744 UBYTE byte;
746 byte = *file_subsection++;
747 file_len--;
749 val |= (byte & 0x7F) << shift;
750 if (!(byte & 0x80))
751 break;
753 shift += 7;
757 switch (tag)
759 case Tag_CPU_arch:
760 DATTR(bug("[ELF.ARM] ARM CPU architecture set to %d\n", val));
762 if (val > ELF_CPU_ARMv7EM)
764 DATTR(bug("[ELF.ARM] Unknown CPU tag value (%d)\n", val));
765 return FALSE;
768 if (arm_cpus[val] > IDosBase(DOSBase)->arm_Arch)
770 DATTR(bug("[ELF.ARM] CPU Requirements too high (system %d, file %d)\n", IDosBase(DOSBase)->arm_Arch, arm_cpus[val]));
771 return FALSE;
773 break;
775 case Tag_FP_arch:
776 DATTR(bug("[ELF.ARM] ARM FPU architecture set to %d\n", val));
778 switch (val)
780 case ELF_FP_None:
781 break;
783 case ELF_FP_v1:
784 case ELF_FP_v2:
785 if (!IDosBase(DOSBase)->arm_VFP)
787 DATTR(bug("[ELF.ARM] VFP required but missing\n"));
788 return FALSE;
790 break;
792 case ELF_FP_v3:
793 case ELF_FP_v3_Short:
794 if (!IDosBase(DOSBase)->arm_VFP_v3)
796 DATTR(bug("[ELF.ARM] VFPv3 required but missing\n"));
797 return FALSE;
799 break;
801 default:
802 /* This includes VFPv4 for now */
803 DATTR(bug("[ELF.ARM] VFP %d required -- unsupported\n", val));
804 return FALSE;
807 break;
811 /* We allow to execute only files which contain attributes section */
812 return TRUE;
814 aeabi_attrs = (void *)aeabi_attrs + aeabi_attrs_size;
815 aeabi_len -= aeabi_attrs_size;
818 return FALSE;
820 attrs = (void *)attrs + attrs_size;
821 len -= attrs_size;
823 return FALSE;
826 #endif
828 BPTR InternalLoadSeg_ELF
830 BPTR file,
831 BPTR table __unused,
832 SIPTR *funcarray,
833 LONG *stack __unused,
834 struct DosLibrary *DOSBase
837 struct elfheader eh;
838 struct sheader *sh;
839 struct sheader *symtab_shndx = NULL;
840 struct sheader *strtab = NULL;
841 BPTR hunks = 0;
842 BPTR *next_hunk_ptr = &hunks;
843 ULONG i;
844 BOOL exec_hunk_seen = FALSE;
845 ULONG int_shnum;
847 /* load and validate ELF header */
848 if (!load_header(file, &eh, funcarray, DOSBase))
849 return 0;
851 int_shnum = read_shnum(file, &eh, funcarray, DOSBase);
852 if (!int_shnum)
853 return 0;
855 /* load section headers */
856 if (!(sh = load_block(file, eh.shoff, int_shnum * eh.shentsize, funcarray, DOSBase)))
857 return 0;
859 #ifdef __arm__
860 for (i = 0; i < int_shnum; i++)
862 if (sh[i].type == SHT_ARM_ATTRIBUTES)
864 ULONG len = sh[i].size;
865 UBYTE *data = load_block(file, sh[i].offset, len, funcarray, DOSBase);
867 if (data)
869 BOOL res = ARM_ParseAttrs(data, len, DOSBase);
871 ilsFreeMem(data, len);
873 if (!res)
875 SetIoErr(ERROR_NOT_EXECUTABLE);
876 goto error;
881 #endif
883 /* Iterate over the section headers in order to do some stuff... */
884 for (i = 0; i < int_shnum; i++)
887 Load the symbol and string table(s).
889 NOTICE: the ELF standard, at the moment (Nov 2002) explicitely states
890 that only one symbol table per file is allowed. However, it
891 also states that this may change in future... we already handle it.
893 if (sh[i].type == SHT_SYMTAB || sh[i].type == SHT_STRTAB || sh[i].type == SHT_SYMTAB_SHNDX)
895 sh[i].addr = load_block(file, sh[i].offset, sh[i].size, funcarray, DOSBase);
896 if (!sh[i].addr)
897 goto error;
899 if (sh[i].type == SHT_STRTAB) {
900 if (strtab == NULL) {
901 strtab = &sh[i];
902 } else {
903 D(bug("[ELF Loader] file contains multiple strtab tables. only using the first one\n"));
907 if (sh[i].type == SHT_SYMTAB_SHNDX) {
908 if (symtab_shndx == NULL)
909 symtab_shndx = &sh[i];
910 else
911 D(bug("[ELF Loader] file contains multiple symtab shndx tables. only using the first one\n"));
916 /* Now that we have the string and symbol tables loaded,
917 * load the rest of the hunks.
919 for (i = 0; i < int_shnum; i++)
921 /* Skip the already loaded hunks */
922 if (sh[i].type == SHT_SYMTAB || sh[i].type == SHT_STRTAB || sh[i].type == SHT_SYMTAB_SHNDX)
923 continue;
925 /* Load the section in memory if needed, and make a hunk out of it */
926 if (sh[i].flags & SHF_ALLOC)
928 if (sh[i].size)
930 /* Only allow alignment if this is an executable hunk
931 or if an executable hunk has been loaded already,
932 so to avoid the situation in which a data hunk has its
933 content displaced from the hunk's header in case it's the
934 first hunk (this happens with Keymaps, for instance). */
935 if (sh[i].flags & SHF_EXECINSTR)
936 exec_hunk_seen = TRUE;
938 if (!load_hunk(file, &next_hunk_ptr, &sh[i], strtab ? strtab->addr : NULL, funcarray, exec_hunk_seen, DOSBase))
939 goto error;
944 /* Relocate the sections */
945 for (i = 0; i < int_shnum; i++)
947 /* Does this relocation section refer to a hunk? If so, addr must be != 0 */
948 if ((sh[i].type == AROS_ELF_REL) && sh[SHINDEX(sh[i].info)].addr)
950 sh[i].addr = load_block(file, sh[i].offset, sh[i].size, funcarray, DOSBase);
951 if (!sh[i].addr || !relocate(&eh, sh, i, symtab_shndx, DOSBase))
952 goto error;
954 ilsFreeMem(sh[i].addr, sh[i].size);
955 sh[i].addr = NULL;
959 /* Everything is loaded now. Register the module at kernel.resource */
960 register_elf(file, hunks, &eh, sh, DOSBase);
961 goto end;
963 error:
965 /* There were some errors, deallocate The hunks */
967 InternalUnLoadSeg(hunks, (VOID_FUNC)funcarray[2]);
968 hunks = 0;
970 end:
973 * Clear the caches to let the CPU see the new data and instructions.
974 * We check for SysBase's lib_Version, since this code is also built
975 * as linklib for AmigaOS version of AROS bootstrap, and it can be
976 * running on AOS 1.3 or lower.
978 if (SysBase->LibNode.lib_Version >= 36)
980 BPTR curr = hunks;
982 while (curr)
984 struct hunk *hunk = BPTR2HUNK(BADDR(curr));
986 CacheClearE(hunk->data, hunk->size, CACRF_ClearD | CACRF_ClearI);
988 curr = hunk->next;
992 /* deallocate the symbol tables */
993 for (i = 0; i < int_shnum; i++)
995 if (((sh[i].type == SHT_SYMTAB) || (sh[i].type == SHT_STRTAB)) && (sh[i].addr != NULL))
996 ilsFreeMem(sh[i].addr, sh[i].size);
999 /* Free the section headers */
1000 ilsFreeMem(sh, int_shnum * eh.shentsize);
1002 return hunks;