r4722@vps: verhaegs | 2007-05-06 13:11:19 -0400
[cake.git] / rom / dos / internalloadseg_elf.c
blobccab2e9d1866ac77582b48d1e9085c6eb510a90a
1 /*
2 Copyright © 1995-2001, 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 <exec/memory.h>
15 #include <proto/exec.h>
16 #include <dos/dosasl.h>
17 #include <proto/dos.h>
18 #include <proto/arossupport.h>
19 #include <aros/asmcall.h>
20 #include "internalloadseg.h"
21 #include "dos_intern.h"
23 #include <aros/debug.h>
24 #include <string.h>
25 #include <stddef.h>
27 #include <aros/macros.h>
29 #define SHT_PROGBITS 1
30 #define SHT_SYMTAB 2
31 #define SHT_STRTAB 3
32 #define SHT_RELA 4
33 #define SHT_NOBITS 8
34 #define SHT_REL 9
36 #define ET_REL 1
38 #define EM_386 3
39 #define EM_68K 4
40 #define EM_PPC 20
41 #define EM_ARM 40
42 #define EM_X86_64 62 /* AMD x86-64 */
44 #define R_386_NONE 0
45 #define R_386_32 1
46 #define R_386_PC32 2
48 /* AMD x86-64 relocations. */
49 #define R_X86_64_NONE 0 /* No reloc */
50 #define R_X86_64_64 1 /* Direct 64 bit */
51 #define R_X86_64_PC32 2 /* PC relative 32 bit signed */
53 #define R_68k_NONE 0
54 #define R_68K_32 1
55 #define R_68K_PC32 4
57 #define R_PPC_NONE 0
58 #define R_PPC_ADDR32 1
59 #define R_PPC_ADDR16_LO 4
60 #define R_PPC_ADDR16_HA 6
61 #define R_PPC_REL24 10
62 #define R_PPC_REL32 26
64 #define R_ARM_NONE 0
65 #define R_ARM_PC24 1
66 #define R_ARM_ABS32 2
68 #define STT_OBJECT 1
69 #define STT_FUNC 2
71 #define SHN_ABS 0xfff1
72 #define SHN_COMMON 0xfff2
73 #define SHN_UNDEF 0
75 #define SHF_ALLOC (1 << 1)
76 #define SHF_EXECINSTR (1 << 2)
78 #define ELF32_ST_TYPE(i) ((i) & 0x0F)
80 #define EI_VERSION 6
81 #define EV_CURRENT 1
83 #define EI_DATA 5
84 #define ELFDATA2LSB 1
85 #define ELFDATA2MSB 2
87 #define EI_CLASS 4
88 #define ELFCLASS32 1
89 #define ELFCLASS64 2 /* 64-bit objects */
91 #define ELF32_R_SYM(val) ((val) >> 8)
92 #define ELF32_R_TYPE(val) ((val) & 0xff)
93 #define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff))
96 struct elfheader
98 UBYTE ident[16];
99 UWORD type;
100 UWORD machine;
101 ULONG version;
102 APTR entry;
103 ULONG phoff;
104 ULONG shoff;
105 ULONG flags;
106 UWORD ehsize;
107 UWORD phentsize;
108 UWORD phnum;
109 UWORD shentsize;
110 UWORD shnum;
111 UWORD shstrndx;
114 struct sheader
116 ULONG name;
117 ULONG type;
118 ULONG flags;
119 APTR addr;
120 ULONG offset;
121 ULONG size;
122 ULONG link;
123 ULONG info;
124 ULONG addralign;
125 ULONG entsize;
128 struct symbol
130 ULONG name; /* Offset of the name string in the string table */
131 ULONG value; /* Varies; eg. the offset of the symbol in its hunk */
132 ULONG size; /* How much memory does the symbol occupy */
133 UBYTE info; /* What kind of symbol is this ? (global, variable, etc) */
134 UBYTE other; /* undefined */
135 UWORD shindex; /* In which section is the symbol defined ? */
138 struct relo
140 ULONG offset; /* Address of the relocation relative to the section it refers to */
141 ULONG info; /* Type of the relocation */
142 #if defined(__mc68000__) || defined (__x86_64__) || defined (__ppc__) || defined (__powerpc__) || defined(__arm__)
143 LONG addend; /* Constant addend used to compute value */
144 #endif
147 struct hunk
149 ULONG size;
150 BPTR next;
151 char data[0];
152 } __attribute__((packed));
154 #define BPTR2HUNK(bptr) ((struct hunk *)((char *)BADDR(bptr) - offsetof(struct hunk, next)))
155 #define HUNK2BPTR(hunk) MKBADDR(&hunk->next)
157 #undef MyRead
158 #undef MyAlloc
159 #undef MyFree
162 #define MyRead(file, buf, size) \
163 AROS_CALL3 \
165 LONG, funcarray[0], \
166 AROS_LCA(BPTR, file, D1), \
167 AROS_LCA(void *, buf, D2), \
168 AROS_LCA(LONG, size, D3), \
169 struct DosLibrary *, DOSBase \
173 #define MyAlloc(size, flags) \
174 AROS_CALL2 \
176 void *, funcarray[1], \
177 AROS_LCA(ULONG, size, D0), \
178 AROS_LCA(ULONG, flags, D1), \
179 struct ExecBase *, SysBase \
183 #define MyFree(addr, size) \
184 AROS_CALL2 \
186 void, funcarray[2], \
187 AROS_LCA(void *, addr, A1), \
188 AROS_LCA(ULONG, size, D0), \
189 struct ExecBase *, SysBase \
192 static int read_block
194 BPTR file,
195 ULONG offset,
196 APTR buffer,
197 ULONG size,
198 LONG *funcarray,
199 struct DosLibrary *DOSBase
202 UBYTE *buf = (UBYTE *)buffer;
203 LONG subsize;
205 if (Seek(file, offset, OFFSET_BEGINNING) < 0)
206 return 0;
208 while (size)
210 subsize = MyRead(file, buf, size);
212 if (subsize <= 0)
214 if (subsize == 0)
215 SetIoErr(ERROR_BAD_HUNK);
217 return 0;
220 buf += subsize;
221 size -= subsize;
224 return 1;
227 static void * load_block
229 BPTR file,
230 ULONG offset,
231 ULONG size,
232 LONG *funcarray,
233 struct DosLibrary *DOSBase
236 void *block = MyAlloc(size, MEMF_ANY);
237 if (block)
239 if (read_block(file, offset, block, size, funcarray, DOSBase))
240 return block;
242 MyFree(block, size);
244 else
245 SetIoErr(ERROR_NO_FREE_STORE);
247 return NULL;
250 static int check_header(struct elfheader *eh, struct DosLibrary *DOSBase)
254 eh->ident[0] != 0x7f ||
255 eh->ident[1] != 'E' ||
256 eh->ident[2] != 'L' ||
257 eh->ident[3] != 'F'
260 D(bug("[ELF Loader] Not an ELF object\n"));
261 SetIoErr(ERROR_NOT_EXECUTABLE);
262 return 0;
267 eh->ident[EI_CLASS] != ELFCLASS32 ||
268 eh->ident[EI_VERSION] != EV_CURRENT ||
269 eh->type != ET_REL ||
271 #if defined(__i386__)
273 eh->ident[EI_DATA] != ELFDATA2LSB ||
274 eh->machine != EM_386
276 #elif defined(__x86_64__)
277 eh->ident[EI_DATA] != ELFDATA2LSB ||
278 eh->machine != EM_X86_64
280 #elif defined(__mc68000__)
282 eh->ident[EI_DATA] != ELFDATA2MSB ||
283 eh->machine != EM_68K
284 #elif defined(__ppc__) || defined(__powerpc__)
285 eh->ident[EI_DATA] != ELFDATA2MSB ||
286 eh->machine != EM_PPC
287 #elif defined(__arm__)
288 eh->ident[EI_DATA] != ELFDATA2LSB ||
289 eh->machine != EM_ARM
290 #warning ARM has not been tested, yet!
291 #else
292 # error Your architecture is not supported
293 #endif
296 D(bug("[ELF Loader] Object is of wrong type\n"));
297 D(bug("[ELF Loader] EI_CLASS is %d - should be %d\n", eh->ident[EI_CLASS], ELFCLASS32));
298 D(bug("[ELF Loader] EI_VERSION is %d - should be %d\n", eh->ident[EI_VERSION], EV_CURRENT));
299 D(bug("[ELF Loader] type is %d - should be %d\n", eh->type, ET_REL));
300 #if defined (__i386__)
301 D(bug("[ELF Loader] EI_DATA is %d - should be %d\n", eh->ident[EI_DATA],ELFDATA2LSB));
302 #elif defined (__mc68000__)
303 D(bug("[ELF Loader] EI_DATA is %d - should be %d\n", eh->ident[EI_DATA],ELFDATA2MSB));
304 #elif defined(__ppc__) || defined(__powerpc__)
305 D(bug("[ELF Loader] EI_DATA is %d - should be %d\n", eh->ident[EI_DATA],ELFDATA2MSB));
306 #elif defined (__arm__)
307 D(bug("[ELF Loader] EI_DATA is %d - should be %d\n", eh->ident[EI_DATA],ELFDATA2MSB));
308 #endif
310 #if defined (__i386__)
311 D(bug("[ELF Loader] machine is %d - should be %d\n", eh->machine, EM_386));
312 #elif defined(__mc68000__)
313 D(bug("[ELF Loader] machine is %d - should be %d\n", eh->machine, EM_68K));
314 #elif defined(__ppc__) || defined(__powerpc__)
315 D(bug("[ELF Loader] machine is %d - should be %d\n", eh->machine, EM_PPC));
316 #elif defined(__arm__)
317 D(bug("[ELF Loader] machine is %d - should be %d\n", eh->machine, EM_ARM));
318 #endif
320 SetIoErr(ERROR_NOT_EXECUTABLE);
321 return 0;
324 return 1;
327 static int load_hunk
329 BPTR file,
330 BPTR **next_hunk_ptr,
331 struct sheader *sh,
332 LONG *funcarray,
333 BOOL do_align,
334 struct DosLibrary *DOSBase
337 struct hunk *hunk;
338 ULONG hunk_size;
340 if (!sh->size)
341 return 1;
343 /* The size of the hunk is the size of the section, plus
344 the size of the hunk structure, plus the size of the alignment (if necessary)*/
345 hunk_size = sh->size + sizeof(struct hunk);
347 if (do_align)
349 hunk_size += sh->addralign;
351 /* Also create space for a trampoline, if necessary */
352 if (sh->flags & SHF_EXECINSTR)
353 hunk_size += sizeof(struct FullJumpVec);
356 hunk = MyAlloc(hunk_size, MEMF_ANY | (sh->type == SHT_NOBITS) ? MEMF_CLEAR : 0);
357 if (hunk)
359 hunk->next = 0;
360 hunk->size = hunk_size;
362 /* In case we are required to honour alignment, and If this section contains
363 executable code, create a trampoline to its beginning, so that even if the
364 alignment requirements make the actual code go much after the end of the
365 hunk structure, the code can still be reached in the usual way. */
366 if (do_align)
368 if (sh->flags & SHF_EXECINSTR)
370 sh->addr = (char *)AROS_ROUNDUP2
372 (ULONG)hunk->data + sizeof(struct FullJumpVec), sh->addralign
374 __AROS_SET_FULLJMP((struct FullJumpVec *)hunk->data, sh->addr);
376 else
377 sh->addr = (char *)AROS_ROUNDUP2((ULONG)hunk->data, sh->addralign);
379 else
380 sh->addr = hunk->data;
382 /* Link the previous one with the new one */
383 BPTR2HUNK(*next_hunk_ptr)->next = HUNK2BPTR(hunk);
385 /* Update the pointer to the previous one, which is now the current one */
386 *next_hunk_ptr = HUNK2BPTR(hunk);
388 if (sh->type != SHT_NOBITS)
389 return read_block(file, sh->offset, sh->addr, sh->size, funcarray, DOSBase);
391 return 1;
395 SetIoErr(ERROR_NO_FREE_STORE);
397 return 0;
400 static int relocate
402 struct elfheader *eh,
403 struct sheader *sh,
404 ULONG shrel_idx,
405 struct DosLibrary *DOSBase
408 struct sheader *shrel = &sh[shrel_idx];
409 struct sheader *shsymtab = &sh[shrel->link];
410 struct sheader *toreloc = &sh[shrel->info];
412 struct symbol *symtab = (struct symbol *)shsymtab->addr;
413 struct relo *rel = (struct relo *)shrel->addr;
414 char *section = toreloc->addr;
416 ULONG numrel = shrel->size / shrel->entsize;
417 ULONG i;
419 struct symbol *SysBase_sym = NULL;
421 for (i=0; i<numrel; i++, rel++)
423 struct symbol *sym = &symtab[ELF32_R_SYM(rel->info)];
424 ULONG *p = (ULONG *)&section[rel->offset];
425 ULONG s;
427 switch (sym->shindex)
430 case SHN_UNDEF:
431 D(bug("[ELF Loader] Undefined symbol '%s' while relocating the section '%s'\n",
432 (STRPTR)sh[shsymtab->link].addr + sym->name,
433 (STRPTR)sh[eh->shstrndx].addr + toreloc->name));
434 SetIoErr(ERROR_BAD_HUNK);
435 return 0;
437 case SHN_COMMON:
438 D(bug("[ELF Loader] COMMON symbol '%s' while relocating the section '%s'\n",
439 (STRPTR)sh[shsymtab->link].addr + sym->name,
440 (STRPTR)sh[eh->shstrndx].addr + toreloc->name));
441 SetIoErr(ERROR_BAD_HUNK);
443 return 0;
445 case SHN_ABS:
446 if (SysBase_sym == NULL)
448 if (strncmp((STRPTR)sh[shsymtab->link].addr + sym->name, "SysBase", 8) == 0)
450 SysBase_sym = sym;
451 goto SysBase_yes;
453 else
454 goto SysBase_no;
456 else
457 if (SysBase_sym == sym)
459 SysBase_yes: s = (ULONG)&SysBase;
461 else
462 SysBase_no: s = sym->value;
463 break;
465 default:
466 s = (ULONG)sh[sym->shindex].addr + sym->value;
469 switch (ELF32_R_TYPE(rel->info))
471 #if defined(__i386__)
473 case R_386_32: /* 32bit absolute */
474 *p += s;
475 break;
477 case R_386_PC32: /* 32bit PC relative */
478 *p += s - (ULONG)p;
479 break;
481 case R_386_NONE:
482 break;
484 #elif defined(__x86_64__)
485 /* These weren't tested */
486 case R_X86_64_64: /* 64bit direct/absolute */
487 *p = s + rel->addend;
488 break;
490 case R_X86_64_PC32: /* PC relative 32 bit signed */
491 *p = s + rel->addend - (ULONG)p;
492 break;
494 case R_X86_64_NONE: /* No reloc */
495 break;
497 #elif defined(__mc68000__)
499 case R_68K_32:
500 *p = s + rel->addend;
501 break;
503 case R_68K_PC32:
504 *p = s + rel->addend - (ULONG)p;
505 break;
507 case R_68k_NONE:
508 break;
510 #elif defined(__ppc__) || defined(__powerpc__)
512 case R_PPC_ADDR32:
513 *p = s + rel->addend;
514 break;
516 case R_PPC_ADDR16_LO:
518 unsigned short *c = (unsigned short *) p;
519 *c = (s + rel->addend) & 0xffff;
521 break;
523 case R_PPC_ADDR16_HA:
525 unsigned short *c = (unsigned short *) p;
526 ULONG temp = s + rel->addend;
527 *c = temp >> 16;
528 if ((temp & 0x8000) != 0)
529 (*c)++;
531 break;
533 case R_PPC_REL24:
534 *p &= ~0x3fffffc;
535 *p |= (s + rel->addend - (ULONG) p) & 0x3fffffc;
536 break;
538 case R_PPC_REL32:
539 *p = s + rel->addend - (ULONG) p;
540 break;
542 case R_PPC_NONE:
543 break;
545 #elif defined(__arm__)
548 * This has not been tested. Taken from ARMELF.pdf
549 * from arm.com page 33ff.
551 case R_ARM_PC24:
552 *p = s + rel->addend - (ULONG)p;
553 break;
555 case R_ARM_ABS32:
556 *p = s + rel->addend;
557 break;
559 case R_ARM_NONE:
560 break;
562 #else
563 # error Your architecture is not supported
564 #endif
566 default:
567 D(bug("[ELF Loader] Unrecognized relocation type %d %d\n", i, ELF32_R_TYPE(rel->info)));
568 SetIoErr(ERROR_BAD_HUNK);
569 return 0;
573 return 1;
576 BPTR InternalLoadSeg_ELF
578 BPTR file,
579 BPTR table __unused,
580 LONG *funcarray,
581 LONG *stack __unused,
582 struct DosLibrary *DOSBase
585 struct elfheader eh;
586 struct sheader *sh;
587 BPTR hunks = 0;
588 BPTR *next_hunk_ptr = &hunks;
589 ULONG i;
590 BOOL exec_hunk_seen = FALSE;
592 /* Load Elf Header and Section Headers */
595 !read_block(file, 0, &eh, sizeof(eh), funcarray, DOSBase) ||
596 !check_header(&eh, DOSBase) ||
597 !(sh = load_block(file, eh.shoff, eh.shnum * eh.shentsize, funcarray, DOSBase))
600 return 0;
603 /* Iterate over the section headers in order to do some stuff... */
604 for (i = 0; i < eh.shnum; i++)
607 Load the symbol and string table(s).
609 NOTICE: the ELF standard, at the moment (Nov 2002) explicitely states
610 that only one symbol table per file is allowed. However, it
611 also states that this may change in future... we already handle it.
613 if (sh[i].type == SHT_SYMTAB || sh[i].type == SHT_STRTAB)
615 sh[i].addr = load_block(file, sh[i].offset, sh[i].size, funcarray, DOSBase);
616 if (!sh[i].addr)
617 goto error;
619 else
620 /* Load the section in memory if needed, and make an hunk out of it */
621 if (sh[i].flags & SHF_ALLOC)
623 if (sh[i].size)
625 /* Only allow alignment if this is an executable hunk
626 or if an executable hunk has been loaded already,
627 so to avoid the situation in which a data hunk has its
628 content displaced from the hunk's header in case it's the
629 first hunk (this happens with Keymaps, for instance). */
630 if (sh[i].flags & SHF_EXECINSTR)
631 exec_hunk_seen = TRUE;
633 if (!load_hunk(file, &next_hunk_ptr, &sh[i], funcarray, exec_hunk_seen, DOSBase))
634 goto error;
640 /* Relocate the sections */
641 for (i = 0; i < eh.shnum; i++)
645 #if defined(__i386__)
647 sh[i].type == SHT_REL &&
649 #elif defined(__x86_64__)
651 sh[i].type == SHT_RELA &&
653 #elif defined(__mc68000__)
655 sh[i].type == SHT_RELA &&
657 #elif defined(__ppc__) || defined(__powerpc__)
659 sh[i].type == SHT_RELA &&
661 #elif defined(__arm__)
662 #warning Missing code for ARM
663 // sh[i].type = SHT_
665 #else
666 # error Your architecture is not supported
667 #endif
669 /* Does this relocation section refer to a hunk? If so, addr must be != 0 */
670 sh[sh[i].info].addr
673 sh[i].addr = load_block(file, sh[i].offset, sh[i].size, funcarray, DOSBase);
674 if (!sh[i].addr || !relocate(&eh, sh, i, DOSBase))
675 goto error;
677 MyFree(sh[i].addr, sh[i].size);
678 sh[i].addr = NULL;
683 goto end;
685 error:
687 /* There were some errors, deallocate The hunks */
689 InternalUnLoadSeg(hunks, (VOID_FUNC)funcarray[2]);
690 hunks = 0;
692 end:
694 /* Clear the caches to let the CPU see the new data and instructions */
696 BPTR curr = hunks;
697 while (curr)
699 struct hunk *hunk = BPTR2HUNK(curr);
701 CacheClearE(hunk->data, hunk->size, CACRF_ClearD | CACRF_ClearI);
703 curr = hunk->next;
707 /* deallocate the symbol tables */
708 for (i = 0; i < eh.shnum; i++)
710 if (((sh[i].type == SHT_SYMTAB) || (sh[i].type == SHT_STRTAB)) && (sh[i].addr != NULL))
711 MyFree(sh[i].addr, sh[i].size);
714 /* Free the section headers */
715 MyFree(sh, eh.shnum * eh.shentsize);
717 return hunks;
720 #undef MyRead1
721 #undef MyAlloc
722 #undef MyFree