Indentation fix, cleanup.
[AROS.git] / rom / dos / internalloadseg_elf.c
blob6dbb6ab74a40846c15c1796772e842e32728f79d
1 /*
2 Copyright © 1995-2013, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Code to dynamically load ELF executables
6 Lang: english
7 */
9 #define DATTR(x)
11 #include <aros/asmcall.h>
12 #include <aros/debug.h>
13 #include <aros/macros.h>
14 #include <exec/memory.h>
15 #include <dos/elf.h>
16 #include <dos/dosasl.h>
17 #include <libraries/debug.h>
18 #include <resources/processor.h>
19 #include <proto/dos.h>
20 #include <proto/arossupport.h>
21 #include <proto/debug.h>
22 #include <proto/exec.h>
24 #include <string.h>
25 #include <stddef.h>
27 #include "internalloadseg.h"
28 #include "dos_intern.h"
29 #include "include/loadseg.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 #define LOADSEG_SMALL_READ 2048 /* Size adjusted by profiling in Callgrind */
43 /* [S]mall [R]eads [Buffer]
45 * Due to a fact that Seek flushes buffers, FRead that is used to do small reads
46 * cannot use the buffer. The problem is visible with C++ executables that
47 * have a big number of small sections and thus do many (in tens of thousands
48 * for Odyssey) very small reads.
50 * */
51 struct SRBuffer
53 ULONG srb_FileOffset;
54 APTR srb_Buffer;
57 static int elf_read_block
59 BPTR file,
60 ULONG offset,
61 APTR buffer,
62 ULONG size,
63 SIPTR *funcarray,
64 struct SRBuffer *srb,
65 struct DosLibrary *DOSBase
68 D(bug("[ELF Loader] elf_read_block (offset=%d, size=%d)\n", offset, size));
70 if (size <= LOADSEG_SMALL_READ && (offset >= srb->srb_FileOffset) &&
71 ((offset + size) <= (srb->srb_FileOffset + LOADSEG_SMALL_READ)) &&
72 srb->srb_Buffer != NULL)
74 CopyMem(srb->srb_Buffer + (offset - srb->srb_FileOffset), buffer, size);
75 return 0;
77 else
79 if (ilsSeek(file, offset, OFFSET_BEGINNING) < 0)
80 return 1;
82 if (size <= LOADSEG_SMALL_READ)
84 if (srb->srb_Buffer == NULL)
85 srb->srb_Buffer = AllocMem(LOADSEG_SMALL_READ, MEMF_ANY);
87 srb->srb_FileOffset = offset;
89 /* Fill the buffer */
90 read_block(file, srb->srb_Buffer, LOADSEG_SMALL_READ, funcarray, DOSBase);
91 /* Re-read, now srb will be used */
92 return elf_read_block(file, offset, buffer, size, funcarray, srb, DOSBase);
94 else
96 return read_block(file, buffer, size, funcarray, DOSBase);
101 static void *load_block
103 BPTR file,
104 ULONG offset,
105 ULONG size,
106 SIPTR *funcarray,
107 struct SRBuffer *srb,
108 struct DosLibrary *DOSBase
111 D(bug("[ELF Loader] Load Block\n"));
112 D(bug("[ELF Loader] (size=%d)\n",size));
113 D(bug("[ELF Loader] (funcarray=0x%x)\n",funcarray));
114 D(bug("[ELF Loader] (funcarray[1]=0x%x)\n",funcarray[1]));
115 void *block = ilsAllocMem(size, MEMF_ANY);
116 if (block)
118 if (!elf_read_block(file, offset, block, size, funcarray, srb, DOSBase))
119 return block;
121 ilsFreeMem(block, size);
123 else
124 SetIoErr(ERROR_NO_FREE_STORE);
126 return NULL;
129 static ULONG read_shnum(BPTR file, struct elfheader *eh, SIPTR *funcarray, struct SRBuffer *srb, struct DosLibrary *DOSBase)
131 ULONG shnum = eh->shnum;
133 /* the ELF header only uses 16 bits to store the count of section headers,
134 * so it can't handle more than 65535 headers. if the count is 0, and an
135 * offset is defined, then the real count can be found in the first
136 * section header (which always exists).
138 * similarly, if the string table index is SHN_XINDEX, then the actual
139 * index is found in the first section header also.
141 * see the System V ABI 2001-04-24 draft for more details.
143 if (eh->shnum == 0)
145 struct sheader sh;
147 if (eh->shoff == 0) {
148 D(bug("[ELF Loader] No section header\n"));
149 SetIoErr(ERROR_NOT_EXECUTABLE);
150 return 0;
153 if (elf_read_block(file, eh->shoff, &sh, sizeof(sh), funcarray, srb, DOSBase))
154 return 0;
156 /* wider section header count is in the size field */
157 shnum = sh.size;
159 /* sanity, if they're still invalid then this isn't elf */
160 if (shnum == 0) {
161 D(bug("[ELF Loader] Empty section header\n"));
162 SetIoErr(ERROR_NOT_EXECUTABLE);
166 return shnum;
169 static int load_header(BPTR file, struct elfheader *eh, SIPTR *funcarray, struct SRBuffer *srb, struct DosLibrary *DOSBase)
171 if (elf_read_block(file, 0, eh, sizeof(struct elfheader), funcarray, srb, DOSBase))
172 return 0;
174 if (eh->ident[0] != 0x7f || eh->ident[1] != 'E' ||
175 eh->ident[2] != 'L' || eh->ident[3] != 'F') {
176 D(bug("[ELF Loader] Not an ELF object\n"));
177 SetIoErr(ERROR_NOT_EXECUTABLE);
178 return 0;
180 D(bug("[ELF Loader] ELF object\n"));
182 /* WANT_CLASS should be defined for your target */
183 if (eh->ident[EI_CLASS] != AROS_ELF_CLASS ||
184 eh->ident[EI_VERSION] != EV_CURRENT ||
185 eh->type != ET_REL ||
186 eh->ident[EI_DATA] != AROS_ELF_DATA ||
187 eh->machine != AROS_ELF_MACHINE)
189 D(bug("[ELF Loader] Object is of wrong type\n"));
190 D(bug("[ELF Loader] EI_CLASS is %d - should be %d\n", eh->ident[EI_CLASS] , AROS_ELF_CLASS ));
191 D(bug("[ELF Loader] EI_VERSION is %d - should be %d\n", eh->ident[EI_VERSION], EV_CURRENT ));
192 D(bug("[ELF Loader] type is %d - should be %d\n", eh->type , ET_REL ));
193 D(bug("[ELF Loader] EI_DATA is %d - should be %d\n", eh->ident[EI_DATA] , AROS_ELF_DATA ));
194 D(bug("[ELF Loader] machine is %d - should be %d\n", eh->machine , AROS_ELF_MACHINE));
196 SetIoErr(ERROR_NOT_EXECUTABLE);
197 return 0;
200 return 1;
203 static int load_hunk
205 BPTR file,
206 BPTR **next_hunk_ptr,
207 struct sheader *sh,
208 CONST_STRPTR strtab,
209 SIPTR *funcarray,
210 BOOL do_align,
211 struct SRBuffer *srb,
212 struct DosLibrary *DOSBase
215 struct hunk *hunk;
216 ULONG hunk_size;
217 ULONG memflags = 0;
219 if (!sh->size)
220 return 1;
222 /* The size of the hunk is the size of the section, plus
223 the size of the hunk structure, plus the size of the alignment (if necessary)*/
224 hunk_size = sh->size + sizeof(struct hunk);
226 if (do_align)
228 hunk_size += sh->addralign;
230 /* Also create space for a trampoline, if necessary */
231 if (sh->flags & SHF_EXECINSTR)
232 hunk_size += sizeof(struct FullJumpVec);
235 if (strtab) {
236 CONST_STRPTR nameext;
238 nameext = strrchr(strtab + sh->name, '.');
239 if (nameext) {
240 if (strcmp(nameext, ".MEMF_CHIP")==0) {
241 memflags |= MEMF_CHIP;
242 } else if (strcmp(nameext, ".MEMF_LOCAL")==0) {
243 memflags |= MEMF_LOCAL;
244 } else if (strcmp(nameext, ".MEMF_KICK")==0) {
245 memflags |= MEMF_KICK;
246 } else if (strcmp(nameext, ".MEMF_FAST")==0) {
247 memflags |= MEMF_FAST;
248 } else if (strcmp(nameext, ".MEMF_PUBLIC")==0) {
249 memflags |= MEMF_PUBLIC;
254 hunk = ilsAllocMem(hunk_size, memflags | MEMF_PUBLIC | (sh->type == SHT_NOBITS ? MEMF_CLEAR : 0));
255 if (hunk)
257 hunk->next = 0;
258 hunk->size = hunk_size;
260 /* In case we are required to honour alignment, and If this section contains
261 executable code, create a trampoline to its beginning, so that even if the
262 alignment requirements make the actual code go much after the end of the
263 hunk structure, the code can still be reached in the usual way. */
264 if (do_align)
266 if (sh->flags & SHF_EXECINSTR)
268 sh->addr = (char *)AROS_ROUNDUP2
270 (IPTR)hunk->data + sizeof(struct FullJumpVec), sh->addralign
272 __AROS_SET_FULLJMP((struct FullJumpVec *)hunk->data, sh->addr);
274 else
275 sh->addr = (char *)AROS_ROUNDUP2((IPTR)hunk->data, sh->addralign);
277 else
278 sh->addr = hunk->data;
280 /* Link the previous one with the new one */
281 BPTR2HUNK(*next_hunk_ptr)->next = HUNK2BPTR(hunk);
283 D(bug("[dos] hunk @ %p, size=%08x, addr @ %p\n", hunk, hunk->size, sh->addr));
285 /* Update the pointer to the previous one, which is now the current one */
286 *next_hunk_ptr = &hunk->next;
288 if (sh->type != SHT_NOBITS)
289 return !elf_read_block(file, sh->offset, sh->addr, sh->size, funcarray, srb, DOSBase);
291 return 1;
295 SetIoErr(ERROR_NO_FREE_STORE);
297 return 0;
300 static int relocate
302 struct elfheader *eh,
303 struct sheader *sh,
304 ULONG shrel_idx,
305 struct sheader *symtab_shndx,
306 struct DosLibrary *DOSBase
309 struct sheader *shrel = &sh[shrel_idx];
310 struct sheader *shsymtab = &sh[shrel->link];
311 struct sheader *toreloc = &sh[shrel->info];
313 struct symbol *symtab = (struct symbol *)shsymtab->addr;
314 struct relo *rel = (struct relo *)shrel->addr;
317 * Ignore relocs if the target section has no allocation. that can happen
318 * eg. with a .debug PROGBITS and a .rel.debug section
320 if (!(toreloc->flags & SHF_ALLOC))
321 return 1;
323 ULONG numrel = shrel->size / shrel->entsize;
324 ULONG i;
326 for (i=0; i<numrel; i++, rel++)
328 struct symbol *sym;
329 ULONG *p;
330 IPTR s;
331 ULONG shindex;
333 #ifdef __arm__
335 * R_ARM_V4BX are actually special marks for the linker.
336 * They even never have a target (shindex == SHN_UNDEF),
337 * so we simply ignore them before doing any checks.
339 if (ELF_R_TYPE(rel->info) == R_ARM_V4BX)
340 continue;
341 #endif
343 sym = &symtab[ELF_R_SYM(rel->info)];
344 p = toreloc->addr + rel->offset;
346 if (sym->shindex != SHN_XINDEX)
347 shindex = sym->shindex;
349 else {
350 if (symtab_shndx == NULL) {
351 D(bug("[ELF Loader] got symbol with shndx 0xfff, but there's no symtab shndx table\n"));
352 SetIoErr(ERROR_BAD_HUNK);
353 return 0;
355 shindex = ((ULONG *)symtab_shndx->addr)[ELF_R_SYM(rel->info)];
358 DB2(bug("[ELF Loader] Processing symbol %s\n", sh[shsymtab->link].addr + sym->name));
360 switch (shindex)
363 case SHN_COMMON:
364 D(bug("[ELF Loader] COMMON symbol '%s'\n",
365 (STRPTR)sh[shsymtab->link].addr + sym->name));
366 SetIoErr(ERROR_BAD_HUNK);
368 return 0;
370 case SHN_ABS:
371 s = sym->value;
372 break;
374 case SHN_UNDEF:
375 if (ELF_R_TYPE(rel->info) != 0) {
376 D(bug("[ELF Loader] Undefined symbol '%s'\n",
377 (STRPTR)sh[shsymtab->link].addr + sym->name));
378 SetIoErr(ERROR_BAD_HUNK);
379 return 0;
381 /* fall through */
383 default:
384 s = (IPTR)sh[shindex].addr + sym->value;
387 switch (ELF_R_TYPE(rel->info))
389 #if defined(__i386__)
391 case R_386_32: /* 32bit absolute */
392 *p += s;
393 break;
395 case R_386_PC32: /* 32bit PC relative */
396 *p += s - (ULONG)p;
397 break;
399 case R_386_NONE:
400 break;
402 #elif defined(__x86_64__)
403 case R_X86_64_64: /* 64bit direct/absolute */
404 *(UQUAD *)p = s + rel->addend;
405 break;
407 case R_X86_64_PC32: /* PC relative 32 bit signed */
408 *(ULONG *)p = s + rel->addend - (IPTR) p;
409 break;
411 case R_X86_64_32:
412 *(ULONG *)p = (UQUAD)s + (UQUAD)rel->addend;
413 break;
415 case R_X86_64_32S:
416 *(LONG *)p = (QUAD)s + (QUAD)rel->addend;
417 break;
419 case R_X86_64_NONE: /* No reloc */
420 break;
422 #elif defined(__mc68000__)
424 case R_68K_32:
425 *p = s + rel->addend;
426 break;
428 case R_68K_16:
429 *(UWORD *)p = s + rel->addend;
430 break;
432 case R_68K_8:
433 *(UBYTE *)p = s + rel->addend;
434 break;
436 case R_68K_PC32:
437 *p = s + rel->addend - (ULONG)p;
438 break;
440 case R_68K_PC16:
441 *(UWORD *)p = s + rel->addend - (ULONG)p;
442 break;
444 case R_68K_PC8:
445 *(UBYTE *)p = s + rel->addend - (ULONG)p;
446 break;
448 case R_68K_NONE:
449 break;
451 #elif defined(__ppc__) || defined(__powerpc__)
453 case R_PPC_ADDR32:
454 *p = s + rel->addend;
455 break;
457 case R_PPC_ADDR16_LO:
459 unsigned short *c = (unsigned short *) p;
460 *c = (s + rel->addend) & 0xffff;
462 break;
464 case R_PPC_ADDR16_HA:
466 unsigned short *c = (unsigned short *) p;
467 ULONG temp = s + rel->addend;
468 *c = temp >> 16;
469 if ((temp & 0x8000) != 0)
470 (*c)++;
472 break;
474 case R_PPC_REL16_LO:
476 unsigned short *c = (unsigned short *) p;
477 *c = (s + rel->addend - (ULONG) p) & 0xffff;
479 break;
481 case R_PPC_REL16_HA:
483 unsigned short *c = (unsigned short *) p;
484 ULONG temp = s + rel->addend - (ULONG) p;
485 *c = temp >> 16;
486 if ((temp & 0x8000) != 0)
487 (*c)++;
489 break;
491 case R_PPC_REL24:
492 *p &= ~0x3fffffc;
493 *p |= (s + rel->addend - (ULONG) p) & 0x3fffffc;
494 break;
496 case R_PPC_REL32:
497 *p = s + rel->addend - (ULONG) p;
498 break;
500 case R_PPC_NONE:
501 break;
503 #elif defined(__arm__)
504 case R_ARM_CALL:
505 case R_ARM_JUMP24:
506 case R_ARM_PC24:
507 case R_ARM_PREL31:
509 /* On ARM the 24 bit offset is shifted by 2 to the right */
510 signed long offset = (*p & 0x00ffffff) << 2;
511 /* If highest bit set, make offset negative */
512 if (offset & 0x02000000)
513 offset -= 0x04000000;
515 if (offset >= 0x02000000 ||
516 offset <= -0x02000000)
518 bug("[ELF Loader] Relocation type %d %d out of range!\n", i, ELF_R_TYPE(rel->info));
519 SetIoErr(ERROR_BAD_HUNK);
520 return 0;
522 offset += s - (ULONG)p;
524 offset >>= 2;
525 *p &= 0xff000000;
526 *p |= offset & 0x00ffffff;
528 break;
530 case R_ARM_THM_CALL:
531 case R_ARM_THM_JUMP24:
533 ULONG upper,lower,sign,j1,j2;
534 LONG offset;
536 upper = *((UWORD *)p);
537 lower = *((UWORD *)p+1);
539 sign = (upper >> 10) & 1;
540 j1 = (lower >> 13) & 1;
541 j2 = (lower >> 11) & 1;
543 offset = (sign << 24) | ((~(j1 ^ sign) & 1) << 23) |
544 ((~(j2 ^ sign) & 1) << 22) |
545 ((upper & 0x03ff) << 12) |
546 ((lower & 0x07ff) << 1);
548 if (offset & 0x01000000)
549 offset -= 0x02000000;
551 if (offset >= 0x01000000 ||
552 offset <= -0x01000000)
554 bug("[ELF Loader] Relocation type %d %d out of range!\n", i, ELF_R_TYPE(rel->info));
555 SetIoErr(ERROR_BAD_HUNK);
556 return 0;
558 offset += s - (ULONG)p;
560 sign = (offset >> 24) & 1;
561 j1 = sign ^ (~(offset >> 23) & 1);
562 j2 = sign ^ (~(offset >> 22) & 1);
564 *(UWORD *)p = (UWORD)((upper & 0xf800) | (sign << 10) |
565 ((offset >> 12) & 0x03ff));
566 *((UWORD *)p + 1) = (UWORD)((lower & 0xd000) |
567 (j1 << 13) | (j2 << 11) | ((offset >> 1) & 0x07ff));
570 break;
572 case R_ARM_THM_MOVW_ABS_NC:
573 case R_ARM_THM_MOVT_ABS:
575 ULONG upper,lower;
576 LONG offset;
578 upper = *((UWORD *)p);
579 lower = *((UWORD *)p+1);
581 offset = ((upper & 0x000f) << 12) |
582 ((upper & 0x0400) << 1) |
583 ((lower & 0x7000) >> 4) |
584 (lower & 0x00ff);
586 offset = (offset ^ 0x8000) - 0x8000;
588 offset += s;
590 if (ELF_R_TYPE(rel->info) == R_ARM_THM_MOVT_ABS)
591 offset >>= 16;
593 *(UWORD *)p = (UWORD)((upper & 0xfbf0) |
594 ((offset & 0xf000) >> 12) |
595 ((offset & 0x0800) >> 1));
596 *((UWORD *)p + 1) = (UWORD)((lower & 0x8f00) |
597 ((offset & 0x0700)<< 4) |
598 (offset & 0x00ff));
600 break;
602 case R_ARM_MOVW_ABS_NC:
603 case R_ARM_MOVT_ABS:
605 signed long offset = *p;
606 offset = ((offset & 0xf0000) >> 4) | (offset & 0xfff);
607 offset = (offset ^ 0x8000) - 0x8000;
609 offset += s;
611 if (ELF_R_TYPE(rel->info) == R_ARM_MOVT_ABS)
612 offset >>= 16;
614 *p &= 0xfff0f000;
615 *p |= ((offset & 0xf000) << 4) | (offset & 0x0fff);
617 break;
619 case R_ARM_TARGET2: /* maps to R_ARM_ABS32 under EABI for AROS*/
620 case R_ARM_TARGET1: /* use for constructors/destructors; maps to
621 R_ARM_ABS32 */
622 case R_ARM_ABS32:
623 *p += s;
624 break;
626 case R_ARM_NONE:
627 break;
629 #else
630 # error Your architecture is not supported
631 #endif
633 default:
634 D(bug("[ELF Loader] Unrecognized relocation type %d %d\n", i, ELF_R_TYPE(rel->info)));
635 SetIoErr(ERROR_BAD_HUNK);
636 return 0;
640 return 1;
643 #ifdef __arm__
646 * On ARM < v6 all LONG accesses must be LONG-aligned
647 * TODO: This is useful and can be moved to some public include file.
649 #if (__ARM_ARCH__ > 5)
651 #define READLONG_UNALIGNED(src) src
653 #else
655 static inline ULONG readlong_unaligned(ULONG *src)
657 ULONG res, tmp;
659 asm volatile(
660 "ldrb %0, [%2, #0]\n\t"
661 "ldrb %1, [%2, #1]\n\t"
662 "orr %0, %0, %1, lsl #8\n\t"
663 "ldrb %1, [%2, #2]\n\t"
664 "orr %0, %0, %1, lsl #16\n\t"
665 "ldrb %1, [%2, #3]\n\t"
666 "orr %0, %0, %1, lsl #24"
667 :"=&r"(res), "=&r"(tmp) : "r"(src)
670 return res;
673 #define READLONG_UNALIGNED(src) readlong_unaligned(&src);
674 #endif
677 * This code parses special .ARM.Attributes section and
678 * extracts system requirements from it. Things like float ABI,
679 * minimum CPU and FPU version are described there.
682 static UBYTE arm_cpus[] =
684 CPUFAMILY_ARM_3,
685 CPUFAMILY_ARM_4,
686 CPUFAMILY_ARM_4T,
687 CPUFAMILY_ARM_5T,
688 CPUFAMILY_ARM_5TE,
689 CPUFAMILY_ARM_5TEJ,
690 CPUFAMILY_ARM_6,
691 CPUFAMILY_ARM_6,
692 CPUFAMILY_ARM_6, /* 6KZ */
693 CPUFAMILY_ARM_6, /* 6T2 */
694 CPUFAMILY_ARM_6, /* 6K */
695 CPUFAMILY_ARM_7,
696 CPUFAMILY_ARM_6, /* 6-M */
697 CPUFAMILY_ARM_6, /* 6S-M */
698 CPUFAMILY_ARM_7 /* 7E-M */
701 static BOOL ARM_ParseAttrs(UBYTE *data, ULONG len, struct DosLibrary *DOSBase)
703 struct attrs_section *attrs;
705 if (data[0] != ATTR_VERSION_CURRENT)
707 DATTR(bug("[ELF.ARM] Unknown attributes version: 0x%02\n", data[0]));
708 return FALSE;
711 attrs = (void *)data + 1;
712 while (len > 0)
714 ULONG attrs_size = READLONG_UNALIGNED(attrs->size);
716 if (!strcmp(attrs->vendor, "aeabi"))
718 struct attrs_subsection *aeabi_attrs = (void *)attrs->vendor + 6;
719 ULONG aeabi_len = attrs_size - 10;
721 DATTR(bug("[ELF.ARM] Found aeabi attributes @ 0x%p (length %u)\n", aeabi_attrs, aeabi_len));
723 while (aeabi_len > 0)
725 ULONG aeabi_attrs_size = READLONG_UNALIGNED(aeabi_attrs->size);
727 if (aeabi_attrs->tag == Tag_File)
729 UBYTE *file_subsection = (void *)aeabi_attrs + sizeof(struct attrs_subsection);
730 UBYTE file_len = aeabi_attrs_size - sizeof(struct attrs_subsection);
732 DATTR(bug("[ELF.ARM] Found file-wide attributes @ 0x%p (length %u)\n", file_subsection, file_len));
734 while (file_len > 0)
736 UBYTE tag, shift;
737 ULONG val = 0;
739 tag = *file_subsection++;
740 file_len--;
742 if (file_len == 0)
744 DATTR(bug("[ELF.ARM] Mailformed attribute tag %d (no data)\n", tag));
745 return FALSE;
748 switch (tag)
750 case Tag_CPU_raw_name:
751 case Tag_CPU_name:
752 case Tag_compatibility:
753 case Tag_also_compatible_with:
754 case Tag_conformance:
755 /* These two are NULL-terminated strings. Just skip. */
756 while (file_len)
758 file_len--;
759 if (*file_subsection++ == 0)
760 break;
762 break;
764 default:
765 /* Read ULEB128 value */
766 shift = 0;
767 while (file_len)
769 UBYTE byte;
771 byte = *file_subsection++;
772 file_len--;
774 val |= (byte & 0x7F) << shift;
775 if (!(byte & 0x80))
776 break;
778 shift += 7;
782 switch (tag)
784 case Tag_CPU_arch:
785 DATTR(bug("[ELF.ARM] ARM CPU architecture set to %d\n", val));
787 if (val > ELF_CPU_ARMv7EM)
789 DATTR(bug("[ELF.ARM] Unknown CPU tag value (%d)\n", val));
790 return FALSE;
793 if (arm_cpus[val] > IDosBase(DOSBase)->arm_Arch)
795 DATTR(bug("[ELF.ARM] CPU Requirements too high (system %d, file %d)\n", IDosBase(DOSBase)->arm_Arch, arm_cpus[val]));
796 return FALSE;
798 break;
800 case Tag_FP_arch:
801 DATTR(bug("[ELF.ARM] ARM FPU architecture set to %d\n", val));
803 switch (val)
805 case ELF_FP_None:
806 break;
808 case ELF_FP_v1:
809 case ELF_FP_v2:
810 if (!IDosBase(DOSBase)->arm_VFP)
812 DATTR(bug("[ELF.ARM] VFP required but missing\n"));
813 return FALSE;
815 break;
817 case ELF_FP_v3:
818 case ELF_FP_v3_Short:
819 if (!IDosBase(DOSBase)->arm_VFP_v3)
821 DATTR(bug("[ELF.ARM] VFPv3 required but missing\n"));
822 return FALSE;
824 break;
826 default:
827 /* This includes VFPv4 for now */
828 DATTR(bug("[ELF.ARM] VFP %d required -- unsupported\n", val));
829 return FALSE;
832 break;
836 /* We allow to execute only files which contain attributes section */
837 return TRUE;
839 aeabi_attrs = (void *)aeabi_attrs + aeabi_attrs_size;
840 aeabi_len -= aeabi_attrs_size;
843 return FALSE;
845 attrs = (void *)attrs + attrs_size;
846 len -= attrs_size;
848 return FALSE;
851 #endif
853 BPTR InternalLoadSeg_ELF
855 BPTR file,
856 BPTR table __unused,
857 SIPTR *funcarray,
858 LONG *stack __unused,
859 struct DosLibrary *DOSBase
862 struct elfheader eh;
863 struct sheader *sh;
864 struct sheader *symtab_shndx = NULL;
865 struct sheader *strtab = NULL;
866 BPTR hunks = 0;
867 BPTR *next_hunk_ptr = &hunks;
868 ULONG i;
869 BOOL exec_hunk_seen = FALSE;
870 ULONG int_shnum;
871 struct SRBuffer srb = { 0 };
873 /* load and validate ELF header */
874 if (!load_header(file, &eh, funcarray, &srb, DOSBase))
875 return 0;
877 int_shnum = read_shnum(file, &eh, funcarray, &srb, DOSBase);
878 if (!int_shnum)
879 return 0;
881 /* load section headers */
882 if (!(sh = load_block(file, eh.shoff, int_shnum * eh.shentsize, funcarray, &srb, DOSBase)))
883 return 0;
885 #ifdef __arm__
886 for (i = 0; i < int_shnum; i++)
888 if (sh[i].type == SHT_ARM_ATTRIBUTES)
890 ULONG len = sh[i].size;
891 UBYTE *data = load_block(file, sh[i].offset, len, funcarray, &srb, DOSBase);
893 if (data)
895 BOOL res = ARM_ParseAttrs(data, len, DOSBase);
897 ilsFreeMem(data, len);
899 if (!res)
901 D(bug("[ELF Loader] Can't parse ARM attributes\n"));
902 SetIoErr(ERROR_NOT_EXECUTABLE);
903 goto error;
908 #endif
910 /* Iterate over the section headers in order to do some stuff... */
911 for (i = 0; i < int_shnum; i++)
914 Load the symbol and string table(s).
916 NOTICE: the ELF standard, at the moment (Nov 2002) explicitely states
917 that only one symbol table per file is allowed. However, it
918 also states that this may change in future... we already handle it.
920 if (sh[i].type == SHT_SYMTAB || sh[i].type == SHT_STRTAB || sh[i].type == SHT_SYMTAB_SHNDX)
922 sh[i].addr = load_block(file, sh[i].offset, sh[i].size, funcarray, &srb, DOSBase);
923 if (!sh[i].addr)
924 goto error;
926 if (sh[i].type == SHT_STRTAB) {
927 if (strtab == NULL) {
928 strtab = &sh[i];
929 } else {
930 D(bug("[ELF Loader] file contains multiple strtab tables. only using the first one\n"));
934 if (sh[i].type == SHT_SYMTAB_SHNDX) {
935 if (symtab_shndx == NULL)
936 symtab_shndx = &sh[i];
937 else
938 D(bug("[ELF Loader] file contains multiple symtab shndx tables. only using the first one\n"));
943 /* Now that we have the string and symbol tables loaded,
944 * load the rest of the hunks.
946 for (i = 0; i < int_shnum; i++)
948 /* Skip the already loaded hunks */
949 if (sh[i].type == SHT_SYMTAB || sh[i].type == SHT_STRTAB || sh[i].type == SHT_SYMTAB_SHNDX)
950 continue;
952 /* Load the section in memory if needed, and make a hunk out of it */
953 if (sh[i].flags & SHF_ALLOC)
955 if (sh[i].size)
957 /* Only allow alignment if this is an executable hunk
958 or if an executable hunk has been loaded already,
959 so to avoid the situation in which a data hunk has its
960 content displaced from the hunk's header in case it's the
961 first hunk (this happens with Keymaps, for instance). */
962 if (sh[i].flags & SHF_EXECINSTR)
963 exec_hunk_seen = TRUE;
965 if (!load_hunk(file, &next_hunk_ptr, &sh[i], strtab ? strtab->addr : NULL, funcarray, exec_hunk_seen, &srb, DOSBase))
966 goto error;
971 /* Relocate the sections */
972 for (i = 0; i < int_shnum; i++)
974 /* Does this relocation section refer to a hunk? If so, addr must be != 0 */
975 if ((sh[i].type == AROS_ELF_REL) && sh[sh[i].info].addr)
977 sh[i].addr = load_block(file, sh[i].offset, sh[i].size, funcarray, &srb, DOSBase);
978 if (!sh[i].addr || !relocate(&eh, sh, i, symtab_shndx, DOSBase))
979 goto error;
981 ilsFreeMem(sh[i].addr, sh[i].size);
982 sh[i].addr = NULL;
986 /* Everything is loaded now. Register the module at kernel.resource */
987 register_elf(file, hunks, &eh, sh, DOSBase);
988 goto end;
990 error:
992 /* There were some errors, deallocate The hunks */
994 InternalUnLoadSeg(hunks, (VOID_FUNC)funcarray[2]);
995 hunks = 0;
997 end:
1000 * Clear the caches to let the CPU see the new data and instructions.
1001 * We check for SysBase's lib_Version, since this code is also built
1002 * as linklib for AmigaOS version of AROS bootstrap, and it can be
1003 * running on AOS 1.3 or lower.
1005 if (SysBase->LibNode.lib_Version >= 36)
1007 BPTR curr = hunks;
1009 while (curr)
1011 struct hunk *hunk = BPTR2HUNK(BADDR(curr));
1013 CacheClearE(hunk->data, hunk->size, CACRF_ClearD | CACRF_ClearI);
1015 curr = hunk->next;
1019 /* deallocate the symbol tables */
1020 for (i = 0; i < int_shnum; i++)
1022 if (((sh[i].type == SHT_SYMTAB) || (sh[i].type == SHT_STRTAB)) && (sh[i].addr != NULL))
1023 ilsFreeMem(sh[i].addr, sh[i].size);
1026 /* Free the section headers */
1027 ilsFreeMem(sh, int_shnum * eh.shentsize);
1029 if (srb.srb_Buffer) FreeMem(srb.srb_Buffer, LOADSEG_SMALL_READ);
1031 return hunks;