Sam and ppc-efika build fixes.
[AROS.git] / arch / ppc-chrp / dos / internalloadseg_elf.c
blob3f46ad7df0aa0b7c27d1889d0c2a7ddbd9cbc51b
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 DEBUG 0
14 #include <aros/config.h>
15 #include <aros/kernel.h>
16 #include <exec/memory.h>
17 #include <proto/exec.h>
18 #include <dos/elf.h>
19 #include <dos/dosasl.h>
20 #include <proto/dos.h>
21 #include <proto/arossupport.h>
22 #include <proto/kernel.h>
23 #include <aros/asmcall.h>
24 #include "internalloadseg.h"
25 #include "dos_intern.h"
27 #include <aros/debug.h>
28 #include <string.h>
29 #include <stddef.h>
31 #include <aros/macros.h>
33 struct hunk
35 ULONG size;
36 BPTR next;
37 char data[0];
38 } __attribute__((packed));
40 #define BPTR2HUNK(bptr) ((struct hunk *)((void *)bptr - offsetof(struct hunk, next)))
41 #define HUNK2BPTR(hunk) MKBADDR(&hunk->next)
43 static int read_block
45 BPTR file,
46 ULONG offset,
47 APTR buffer,
48 ULONG size,
49 SIPTR *funcarray,
50 struct DosLibrary *DOSBase
53 UBYTE *buf = (UBYTE *)buffer;
54 LONG subsize;
56 if (ilsSeek(file, offset, OFFSET_BEGINNING) < 0)
57 return 0;
59 while (size)
61 subsize = ilsRead(file, buf, size);
63 if (subsize <= 0)
65 if (subsize == 0)
66 SetIoErr(ERROR_BAD_HUNK);
68 return 0;
71 buf += subsize;
72 size -= subsize;
75 return 1;
78 static void *load_block
80 BPTR file,
81 ULONG offset,
82 ULONG size,
83 SIPTR *funcarray,
84 struct DosLibrary *DOSBase
87 D(bug("[ELF Loader] Load Block\n"));
88 D(bug("[ELF Loader] (size=%d)\n",size));
89 D(bug("[ELF Loader] (funcarray=0x%x)\n",funcarray));
90 D(bug("[ELF Loader] (funcarray[1]=0x%x)\n",funcarray[1]));
91 void *block = ilsAllocMem(size, MEMF_ANY);
92 if (block)
94 if (read_block(file, offset, block, size, funcarray, DOSBase))
95 return block;
97 ilsFreeMem(block, size);
99 else
100 SetIoErr(ERROR_NO_FREE_STORE);
102 return NULL;
105 static ULONG read_shnum(BPTR file, struct elfheader *eh, SIPTR *funcarray, struct DosLibrary *DOSBase)
107 ULONG shnum = eh->shnum;
109 /* the ELF header only uses 16 bits to store the count of section headers,
110 * so it can't handle more than 65535 headers. if the count is 0, and an
111 * offset is defined, then the real count can be found in the first
112 * section header (which always exists).
114 * similarly, if the string table index is SHN_XINDEX, then the actual
115 * index is found in the first section header also.
117 * see the System V ABI 2001-04-24 draft for more details.
119 if (eh->shnum == 0)
121 struct sheader sh;
123 if (eh->shoff == 0) {
124 SetIoErr(ERROR_NOT_EXECUTABLE);
125 return 0;
128 if (!read_block(file, eh->shoff, &sh, sizeof(sh), funcarray, DOSBase))
129 return 0;
131 /* wider section header count is in the size field */
132 shnum = sh.size;
134 /* sanity, if they're still invalid then this isn't elf */
135 if (shnum == 0)
136 SetIoErr(ERROR_NOT_EXECUTABLE);
139 return shnum;
142 static void register_elf(BPTR file, BPTR hunks, struct elfheader *eh, struct sheader *sh, struct DosLibrary *DOSBase)
144 #ifdef KrnRegisterModule
145 if (KernelBase)
147 char buffer[512];
149 if (NameFromFH(file, buffer, sizeof(buffer))) {
150 char *nameptr = buffer;
151 struct ELF_DebugInfo dbg = {eh, sh};
153 /* gdb support needs full paths */
154 #if !AROS_MODULES_DEBUG
155 /* First, go through the name, till end of the string */
156 while(*nameptr++);
157 /* Now, go back until either ":" or "/" is found */
158 while(nameptr > buffer && nameptr[-1] != ':' && nameptr[-1] != '/')
159 nameptr--;
160 #endif
161 KrnRegisterModule(nameptr, sh, &eh);
162 //KrnRegisterModule(nameptr, hunks, DEBUG_ELF, &dbg);
165 #endif
168 static int load_header(BPTR file, struct elfheader *eh, SIPTR *funcarray, struct DosLibrary *DOSBase) {
169 ilsSeek(file, OFFSET_BEGINNING, 0);
170 if (!read_block(file, 0, eh, sizeof(struct elfheader), funcarray, DOSBase))
171 return 0;
173 if (eh->ident[0] != 0x7f || eh->ident[1] != 'E' ||
174 eh->ident[2] != 'L' || eh->ident[3] != 'F') {
175 D(bug("[ELF Loader] Not an ELF object\n"));
176 SetIoErr(ERROR_NOT_EXECUTABLE);
177 return 0;
179 D(bug("[ELF Loader] ELF object\n"));
181 /* WANT_CLASS should be defined for your target */
182 if (eh->ident[EI_CLASS] != AROS_ELF_CLASS ||
183 eh->ident[EI_VERSION] != EV_CURRENT ||
184 eh->type != ET_REL ||
185 eh->ident[EI_DATA] != AROS_ELF_DATA ||
186 eh->machine != AROS_ELF_MACHINE)
188 D(bug("[ELF Loader] Object is of wrong type\n"));
189 D(bug("[ELF Loader] EI_CLASS is %d - should be %d\n", eh->ident[EI_CLASS] , AROS_ELF_CLASS ));
190 D(bug("[ELF Loader] EI_VERSION is %d - should be %d\n", eh->ident[EI_VERSION], EV_CURRENT ));
191 D(bug("[ELF Loader] type is %d - should be %d\n", eh->type , ET_REL ));
192 D(bug("[ELF Loader] EI_DATA is %d - should be %d\n", eh->ident[EI_DATA] , AROS_ELF_DATA ));
193 D(bug("[ELF Loader] machine is %d - should be %d\n", eh->machine , AROS_ELF_MACHINE));
195 SetIoErr(ERROR_NOT_EXECUTABLE);
196 return 0;
199 return 1;
202 static int load_hunk
204 BPTR file,
205 BPTR **next_hunk_ptr,
206 struct sheader *sh,
207 SIPTR *funcarray,
208 BOOL do_align,
209 struct DosLibrary *DOSBase
212 struct hunk *hunk;
213 ULONG hunk_size;
215 if (!sh->size)
216 return 1;
218 /* The size of the hunk is the size of the section, plus
219 the size of the hunk structure, plus the size of the alignment (if necessary)*/
220 hunk_size = sh->size + sizeof(struct hunk);
222 if (do_align)
224 hunk_size += sh->addralign;
226 /* Also create space for a trampoline, if necessary */
227 if (sh->flags & SHF_EXECINSTR)
228 hunk_size += sizeof(struct FullJumpVec);
231 hunk = ilsAllocMem(hunk_size, MEMF_ANY | (sh->type == SHT_NOBITS) ? MEMF_CLEAR : 0);
232 if (hunk)
234 hunk->next = 0;
235 hunk->size = hunk_size;
237 /* In case we are required to honour alignment, and If this section contains
238 executable code, create a trampoline to its beginning, so that even if the
239 alignment requirements make the actual code go much after the end of the
240 hunk structure, the code can still be reached in the usual way. */
241 if (do_align)
243 if (sh->flags & SHF_EXECINSTR)
245 sh->addr = (char *)AROS_ROUNDUP2
247 (IPTR)hunk->data + sizeof(struct FullJumpVec), sh->addralign
249 __AROS_SET_FULLJMP((struct FullJumpVec *)hunk->data, sh->addr);
251 else
252 sh->addr = (char *)AROS_ROUNDUP2((IPTR)hunk->data, sh->addralign);
254 else
255 sh->addr = hunk->data;
257 /* Link the previous one with the new one */
258 BPTR2HUNK(*next_hunk_ptr)->next = HUNK2BPTR(hunk);
260 D(bug("[dos] hunk @ %p, size=%08x, addr @ %p\n", hunk, hunk->size, sh->addr));
262 /* Update the pointer to the previous one, which is now the current one */
263 *next_hunk_ptr = &hunk->next;
265 if (sh->type != SHT_NOBITS)
266 return read_block(file, sh->offset, sh->addr, sh->size, funcarray, DOSBase);
268 return 1;
272 SetIoErr(ERROR_NO_FREE_STORE);
274 return 0;
277 static int relocate
279 struct elfheader *eh,
280 struct sheader *sh,
281 ULONG shrel_idx,
282 struct sheader *symtab_shndx,
283 struct DosLibrary *DOSBase
286 struct sheader *shrel = &sh[shrel_idx];
287 struct sheader *shsymtab = &sh[SHINDEX(shrel->link)];
288 struct sheader *toreloc = &sh[SHINDEX(shrel->info)];
290 struct symbol *symtab = (struct symbol *)shsymtab->addr;
291 struct relo *rel = (struct relo *)shrel->addr;
294 * Ignore relocs if the target section has no allocation. that can happen
295 * eg. with a .debug PROGBITS and a .rel.debug section
297 if (!(toreloc->flags & SHF_ALLOC))
298 return 1;
300 ULONG numrel = shrel->size / shrel->entsize;
301 ULONG i;
303 struct symbol *SysBase_sym = NULL;
305 for (i=0; i<numrel; i++, rel++)
307 struct symbol *sym;
308 ULONG *p;
309 IPTR s;
310 ULONG shindex;
312 #ifdef __arm__
314 * R_ARM_V4BX are actually special marks for the linker.
315 * They even never have a target (shindex == SHN_UNDEF),
316 * so we simply ignore them before doing any checks.
318 if (ELF_R_TYPE(rel->info) == R_ARM_V4BX)
319 continue;
320 #endif
322 sym = &symtab[ELF_R_SYM(rel->info)];
323 p = toreloc->addr + rel->offset;
325 if (sym->shindex != SHN_XINDEX)
326 shindex = sym->shindex;
328 else {
329 if (symtab_shndx == NULL) {
330 D(bug("[ELF Loader] got symbol with shndx 0xfff, but there's no symtab shndx table\n"));
331 SetIoErr(ERROR_BAD_HUNK);
332 return 0;
334 shindex = ((ULONG *)symtab_shndx->addr)[ELF_R_SYM(rel->info)];
337 DB2(bug("[ELF Loader] Processing symbol %s\n", sh[SHINDEX(shsymtab->link)].addr + sym->name));
339 switch (shindex)
342 case SHN_UNDEF:
343 D(bug("[ELF Loader] Undefined symbol '%s'\n",
344 (STRPTR)sh[SHINDEX(shsymtab->link)].addr + sym->name));
345 SetIoErr(ERROR_BAD_HUNK);
346 return 0;
348 case SHN_COMMON:
349 D(bug("[ELF Loader] COMMON symbol '%s'\n",
350 (STRPTR)sh[SHINDEX(shsymtab->link)].addr + sym->name));
351 SetIoErr(ERROR_BAD_HUNK);
353 return 0;
355 case SHN_ABS:
356 if (SysBase_sym == NULL)
358 if (strncmp((STRPTR)sh[SHINDEX(shsymtab->link)].addr + sym->name, "SysBase", 8) == 0)
360 SysBase_sym = sym;
361 goto SysBase_yes;
363 else
364 goto SysBase_no;
366 else
367 if (SysBase_sym == sym)
369 SysBase_yes: s = (IPTR)&SysBase;
371 else
372 SysBase_no: s = sym->value;
373 break;
375 default:
376 s = (IPTR)sh[SHINDEX(shindex)].addr + sym->value;
379 switch (ELF_R_TYPE(rel->info))
381 #if defined(__i386__)
383 case R_386_32: /* 32bit absolute */
384 *p += s;
385 break;
387 case R_386_PC32: /* 32bit PC relative */
388 *p += s - (ULONG)p;
389 break;
391 case R_386_NONE:
392 break;
394 #elif defined(__x86_64__)
395 case R_X86_64_64: /* 64bit direct/absolute */
396 *(UQUAD *)p = s + rel->addend;
397 break;
399 case R_X86_64_PC32: /* PC relative 32 bit signed */
400 *(ULONG *)p = s + rel->addend - (IPTR) p;
401 break;
403 case R_X86_64_32:
404 *(ULONG *)p = (UQUAD)s + (UQUAD)rel->addend;
405 break;
407 case R_X86_64_32S:
408 *(LONG *)p = (QUAD)s + (QUAD)rel->addend;
409 break;
411 case R_X86_64_NONE: /* No reloc */
412 break;
414 #elif defined(__mc68000__)
416 case R_68K_32:
417 *p = s + rel->addend;
418 break;
420 case R_68K_PC32:
421 *p = s + rel->addend - (ULONG)p;
422 break;
424 case R_68k_NONE:
425 break;
427 #elif defined(__ppc__) || defined(__powerpc__)
429 case R_PPC_ADDR32:
430 *p = s + rel->addend;
431 break;
433 case R_PPC_ADDR16_LO:
435 unsigned short *c = (unsigned short *) p;
436 *c = (s + rel->addend) & 0xffff;
438 break;
440 case R_PPC_ADDR16_HA:
442 unsigned short *c = (unsigned short *) p;
443 ULONG temp = s + rel->addend;
444 *c = temp >> 16;
445 if ((temp & 0x8000) != 0)
446 (*c)++;
448 break;
450 case R_PPC_REL16_LO:
452 unsigned short *c = (unsigned short *) p;
453 *c = (s + rel->addend - (ULONG) p) & 0xffff;
455 break;
457 case R_PPC_REL16_HA:
459 unsigned short *c = (unsigned short *) p;
460 ULONG temp = s + rel->addend - (ULONG) p;
461 *c = temp >> 16;
462 if ((temp & 0x8000) != 0)
463 (*c)++;
465 break;
467 case R_PPC_REL24:
468 *p &= ~0x3fffffc;
469 *p |= (s + rel->addend - (ULONG) p) & 0x3fffffc;
470 break;
472 case R_PPC_REL32:
473 *p = s + rel->addend - (ULONG) p;
474 break;
476 case R_PPC_NONE:
477 break;
479 #elif defined(__arm__)
480 case R_ARM_CALL:
481 case R_ARM_JUMP24:
482 case R_ARM_PC24:
484 /* On ARM the 24 bit offset is shifted by 2 to the right */
485 signed long offset = (*p & 0x00ffffff) << 2;
486 /* If highest bit set, make offset negative */
487 if (offset & 0x02000000)
488 offset -= 0x04000000;
490 offset += s - (uint32_t)p;
492 offset >>= 2;
493 *p &= 0xff000000;
494 *p |= offset & 0x00ffffff;
496 break;
498 case R_ARM_MOVW_ABS_NC:
499 case R_ARM_MOVT_ABS:
501 signed long offset = *p;
502 offset = ((offset & 0xf0000) >> 4) | (offset & 0xfff);
503 offset = (offset ^ 0x8000) - 0x8000;
505 offset += s;
507 if (ELF_R_TYPE(rel->info) == R_ARM_MOVT_ABS)
508 offset >>= 16;
510 *p &= 0xfff0f000;
511 *p |= ((offset & 0xf000) << 4) | (offset & 0x0fff);
513 break;
515 case R_ARM_ABS32:
516 *p += s;
517 break;
519 case R_ARM_NONE:
520 break;
522 #else
523 # error Your architecture is not supported
524 #endif
526 default:
527 D(bug("[ELF Loader] Unrecognized relocation type %d %d\n", i, ELF_R_TYPE(rel->info)));
528 SetIoErr(ERROR_BAD_HUNK);
529 return 0;
533 return 1;
536 BPTR InternalLoadSeg_ELF
538 BPTR file,
539 BPTR table __unused,
540 SIPTR *funcarray,
541 LONG *stack __unused,
542 struct DosLibrary *DOSBase
545 struct elfheader eh;
546 struct sheader *sh;
547 struct sheader *symtab_shndx = NULL;
548 BPTR hunks = 0;
549 BPTR *next_hunk_ptr = &hunks;
550 ULONG i;
551 BOOL exec_hunk_seen = FALSE;
552 ULONG int_shnum;
554 /* load and validate ELF header */
555 if (!load_header(file, &eh, funcarray, DOSBase))
556 return 0;
558 int_shnum = read_shnum(file, &eh, funcarray, DOSBase);
559 if (!int_shnum)
560 return 0;
562 /* load section headers */
563 if (!(sh = load_block(file, eh.shoff, int_shnum * eh.shentsize, funcarray, DOSBase)))
564 return 0;
566 /* Iterate over the section headers in order to do some stuff... */
567 for (i = 0; i < int_shnum; i++)
570 Load the symbol and string table(s).
572 NOTICE: the ELF standard, at the moment (Nov 2002) explicitely states
573 that only one symbol table per file is allowed. However, it
574 also states that this may change in future... we already handle it.
576 if (sh[i].type == SHT_SYMTAB || sh[i].type == SHT_STRTAB || sh[i].type == SHT_SYMTAB_SHNDX)
578 sh[i].addr = load_block(file, sh[i].offset, sh[i].size, funcarray, DOSBase);
579 if (!sh[i].addr)
580 goto error;
582 if (sh[i].type == SHT_SYMTAB_SHNDX) {
583 if (symtab_shndx == NULL)
584 symtab_shndx = &sh[i];
585 else
586 D(bug("[ELF Loader] file contains multiple symtab shndx tables. only using the first one\n"));
589 else
590 /* Load the section in memory if needed, and make an hunk out of it */
591 if (sh[i].flags & SHF_ALLOC)
593 if (sh[i].size)
595 /* Only allow alignment if this is an executable hunk
596 or if an executable hunk has been loaded already,
597 so to avoid the situation in which a data hunk has its
598 content displaced from the hunk's header in case it's the
599 first hunk (this happens with Keymaps, for instance). */
600 if (sh[i].flags & SHF_EXECINSTR)
601 exec_hunk_seen = TRUE;
603 if (!load_hunk(file, &next_hunk_ptr, &sh[i], funcarray, exec_hunk_seen, DOSBase))
604 goto error;
610 /* Relocate the sections */
611 for (i = 0; i < int_shnum; i++)
613 /* Does this relocation section refer to a hunk? If so, addr must be != 0 */
614 if ((sh[i].type == AROS_ELF_REL) && sh[SHINDEX(sh[i].info)].addr)
616 sh[i].addr = load_block(file, sh[i].offset, sh[i].size, funcarray, DOSBase);
617 if (!sh[i].addr || !relocate(&eh, sh, i, symtab_shndx, DOSBase))
618 goto error;
620 ilsFreeMem(sh[i].addr, sh[i].size);
621 sh[i].addr = NULL;
625 /* Everything is loaded now. Register the module at kernel.resource */
626 register_elf(file, hunks, &eh, sh, DOSBase);
627 goto end;
629 error:
631 /* There were some errors, deallocate The hunks */
633 InternalUnLoadSeg(hunks, (VOID_FUNC)funcarray[2]);
634 hunks = 0;
636 end:
638 /* Clear the caches to let the CPU see the new data and instructions */
640 BPTR curr = hunks;
641 while (curr)
643 struct hunk *hunk = BPTR2HUNK(BADDR(curr));
645 CacheClearE(hunk->data, hunk->size, CACRF_ClearD | CACRF_ClearI);
647 curr = hunk->next;
651 /* deallocate the symbol tables */
652 for (i = 0; i < int_shnum; i++)
654 if (((sh[i].type == SHT_SYMTAB) || (sh[i].type == SHT_STRTAB)) && (sh[i].addr != NULL))
655 ilsFreeMem(sh[i].addr, sh[i].size);
658 /* Free the section headers */
659 ilsFreeMem(sh, int_shnum * eh.shentsize);
661 return hunks;