Disable DOS requesters while checking for available clipboard paths.
[AROS.git] / arch / ppc-sam440 / dos / internalloadseg_elf.c
blobd2684a1e67fad71ca644ca37ff6b68b2dc805de1
1 /*
2 Copyright © 1995-2010, 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 #include "elf_intern.h"
35 int read_block
37 BPTR file,
38 ULONG offset,
39 APTR buffer,
40 ULONG size,
41 SIPTR *funcarray,
42 struct DosLibrary *DOSBase
45 UBYTE *buf = (UBYTE *)buffer;
46 LONG subsize;
48 if (Seek(file, offset, OFFSET_BEGINNING) < 0)
49 return 0;
51 while (size)
53 subsize = MyRead(file, buf, size);
55 if (subsize <= 0)
57 if (subsize == 0)
58 SetIoErr(ERROR_BAD_HUNK);
60 return 0;
63 buf += subsize;
64 size -= subsize;
67 return 1;
70 void *load_block
72 BPTR file,
73 ULONG offset,
74 ULONG size,
75 SIPTR *funcarray,
76 struct DosLibrary *DOSBase
79 D(bug("[ELF Loader] Load Block\n"));
80 D(bug("[ELF Loader] (size=%d)\n",size));
81 D(bug("[ELF Loader] (funcarray=0x%x)\n",funcarray));
82 D(bug("[ELF Loader] (funcarray[1]=0x%x)\n",funcarray[1]));
83 void *block = MyAlloc(size, MEMF_ANY);
84 if (block)
86 if (read_block(file, offset, block, size, funcarray, DOSBase))
87 return block;
89 MyFree(block, size);
91 else
92 SetIoErr(ERROR_NO_FREE_STORE);
94 return NULL;
97 int load_first_header(BPTR file, struct elfheader *eh, SIPTR *funcarray, ULONG *shnum, ULONG *shstrndx, struct DosLibrary *DOSBase)
99 *shnum = eh->shnum;
100 *shstrndx = eh->shstrndx;
102 /* the ELF header only uses 16 bits to store the count of section headers,
103 * so it can't handle more than 65535 headers. if the count is 0, and an
104 * offset is defined, then the real count can be found in the first
105 * section header (which always exists).
107 * similarly, if the string table index is SHN_XINDEX, then the actual
108 * index is found in the first section header also.
110 * see the System V ABI 2001-04-24 draft for more details.
112 if (eh->shnum == 0 || eh->shstrndx == SHN_XINDEX)
114 struct sheader sh;
116 if (eh->shoff == 0) {
117 SetIoErr(ERROR_NOT_EXECUTABLE);
118 return 0;
121 if (!read_block(file, eh->shoff, &sh, sizeof(sh), funcarray, DOSBase))
122 return 0;
124 /* wider section header count is in the size field */
125 if (eh->shnum == 0)
126 *shnum = sh.size;
128 /* wider string table index is in the link field */
129 if (eh->shstrndx == SHN_XINDEX)
130 *shstrndx = sh.link;
132 /* sanity, if they're still invalid then this isn't elf */
133 if (*shnum == 0 || *shstrndx == SHN_XINDEX)
135 SetIoErr(ERROR_NOT_EXECUTABLE);
136 return 0;
140 return 1;
143 void register_elf(BPTR file, BPTR hunks, struct elfheader *eh, struct sheader *sh, struct DosLibrary *DOSBase)
145 #ifdef KrnRegisterModule
146 if (KernelBase)
148 char buffer[512];
150 if (NameFromFH(file, buffer, sizeof(buffer))) {
151 char *nameptr = buffer;
152 struct ELF_DebugInfo dbg = {eh, sh};
154 /* gdb support needs full paths */
155 #if !AROS_MODULES_DEBUG
156 /* First, go through the name, till end of the string */
157 while(*nameptr++);
158 /* Now, go back until either ":" or "/" is found */
159 while(nameptr > buffer && nameptr[-1] != ':' && nameptr[-1] != '/')
160 nameptr--;
161 #endif
162 KrnRegisterModule(nameptr, sh, &eh);
163 //KrnRegisterModule(nameptr, hunks, DEBUG_ELF, &dbg);
166 #endif
169 static int load_header(BPTR file, struct elfheader *eh, SIPTR *funcarray, struct DosLibrary *DOSBase) {
170 Seek(file, OFFSET_BEGINNING, 0);
171 if (!read_block(file, 0, eh, sizeof(struct elfheader), funcarray, 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] != WANT_CLASS ||
184 eh->ident[EI_VERSION] != EV_CURRENT ||
185 eh->type != ET_REL ||
186 eh->ident[EI_DATA] != WANT_BYTE_ORDER ||
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] , WANT_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] , WANT_BYTE_ORDER));
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 SIPTR *funcarray,
209 BOOL do_align,
210 struct DosLibrary *DOSBase
213 struct hunk *hunk;
214 ULONG hunk_size;
216 if (!sh->size)
217 return 1;
219 /* The size of the hunk is the size of the section, plus
220 the size of the hunk structure, plus the size of the alignment (if necessary)*/
221 hunk_size = sh->size + sizeof(struct hunk);
223 if (do_align)
225 hunk_size += sh->addralign;
227 /* Also create space for a trampoline, if necessary */
228 if (sh->flags & SHF_EXECINSTR)
229 hunk_size += sizeof(struct FullJumpVec);
232 hunk = MyAlloc(hunk_size, MEMF_ANY | (sh->type == SHT_NOBITS) ? MEMF_CLEAR : 0);
233 if (hunk)
235 hunk->next = 0;
236 hunk->size = hunk_size;
238 /* In case we are required to honour alignment, and If this section contains
239 executable code, create a trampoline to its beginning, so that even if the
240 alignment requirements make the actual code go much after the end of the
241 hunk structure, the code can still be reached in the usual way. */
242 if (do_align)
244 if (sh->flags & SHF_EXECINSTR)
246 sh->addr = (char *)AROS_ROUNDUP2
248 (IPTR)hunk->data + sizeof(struct FullJumpVec), sh->addralign
250 __AROS_SET_FULLJMP((struct FullJumpVec *)hunk->data, sh->addr);
252 else
253 sh->addr = (char *)AROS_ROUNDUP2((IPTR)hunk->data, sh->addralign);
255 else
256 sh->addr = hunk->data;
258 /* Link the previous one with the new one */
259 BPTR2HUNK(*next_hunk_ptr)->next = HUNK2BPTR(hunk);
261 D(bug("[dos] hunk @ %p, size=%08x, addr @ %p\n", hunk, hunk->size, sh->addr));
263 /* Update the pointer to the previous one, which is now the current one */
264 *next_hunk_ptr = &hunk->next;
266 if (sh->type != SHT_NOBITS)
267 return read_block(file, sh->offset, sh->addr, sh->size, funcarray, DOSBase);
269 return 1;
273 SetIoErr(ERROR_NO_FREE_STORE);
275 return 0;
278 int relocate
280 struct elfheader *eh,
281 struct sheader *sh,
282 ULONG shrel_idx,
283 struct sheader *symtab_shndx,
284 struct DosLibrary *DOSBase
287 struct sheader *shrel = &sh[shrel_idx];
288 struct sheader *shsymtab = &sh[SHINDEX(shrel->link)];
289 struct sheader *toreloc = &sh[SHINDEX(shrel->info)];
291 struct symbol *symtab = (struct symbol *)shsymtab->addr;
292 struct relo *rel = (struct relo *)shrel->addr;
293 char *section = toreloc->addr;
295 /* this happens if the target section has no allocation. that can happen
296 * eg. with a .debug PROGBITS and a .rel.debug section */
297 if (section == NULL)
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 = &symtab[ELF_R_SYM(rel->info)];
308 ULONG *p = (ULONG *)&section[rel->offset];
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 if (sym->shindex != SHN_XINDEX)
323 shindex = sym->shindex;
325 else {
326 if (symtab_shndx == NULL) {
327 D(bug("[ELF Loader] got symbol with shndx 0xfff, but there's no symtab shndx table\n"));
328 SetIoErr(ERROR_BAD_HUNK);
329 return 0;
331 shindex = ((ULONG *)symtab_shndx->addr)[ELF_R_SYM(rel->info)];
334 DB2(bug("[ELF Loader] Processing symbol %s\n", sh[SHINDEX(shsymtab->link)].addr + sym->name));
336 switch (shindex)
339 case SHN_UNDEF:
340 D(bug("[ELF Loader] Undefined symbol '%s'\n",
341 (STRPTR)sh[SHINDEX(shsymtab->link)].addr + sym->name));
342 SetIoErr(ERROR_BAD_HUNK);
343 return 0;
345 case SHN_COMMON:
346 D(bug("[ELF Loader] COMMON symbol '%s'\n",
347 (STRPTR)sh[SHINDEX(shsymtab->link)].addr + sym->name));
348 SetIoErr(ERROR_BAD_HUNK);
350 return 0;
352 case SHN_ABS:
353 if (SysBase_sym == NULL)
355 if (strncmp((STRPTR)sh[SHINDEX(shsymtab->link)].addr + sym->name, "SysBase", 8) == 0)
357 SysBase_sym = sym;
358 goto SysBase_yes;
360 else
361 goto SysBase_no;
363 else
364 if (SysBase_sym == sym)
366 SysBase_yes: s = (IPTR)&SysBase;
368 else
369 SysBase_no: s = sym->value;
370 break;
372 default:
373 s = (IPTR)sh[SHINDEX(shindex)].addr + sym->value;
376 switch (ELF_R_TYPE(rel->info))
378 #if defined(__i386__)
380 case R_386_32: /* 32bit absolute */
381 *p += s;
382 break;
384 case R_386_PC32: /* 32bit PC relative */
385 *p += s - (ULONG)p;
386 break;
388 case R_386_NONE:
389 break;
391 #elif defined(__x86_64__)
392 case R_X86_64_64: /* 64bit direct/absolute */
393 *(UQUAD *)p = s + rel->addend;
394 break;
396 case R_X86_64_PC32: /* PC relative 32 bit signed */
397 *(ULONG *)p = s + rel->addend - (IPTR) p;
398 break;
400 case R_X86_64_32:
401 *(ULONG *)p = (UQUAD)s + (UQUAD)rel->addend;
402 break;
404 case R_X86_64_32S:
405 *(LONG *)p = (QUAD)s + (QUAD)rel->addend;
406 break;
408 case R_X86_64_NONE: /* No reloc */
409 break;
411 #elif defined(__mc68000__)
413 case R_68K_32:
414 *p = s + rel->addend;
415 break;
417 case R_68K_PC32:
418 *p = s + rel->addend - (ULONG)p;
419 break;
421 case R_68k_NONE:
422 break;
424 #elif defined(__ppc__) || defined(__powerpc__)
426 case R_PPC_ADDR32:
427 *p = s + rel->addend;
428 break;
430 case R_PPC_ADDR16_LO:
432 unsigned short *c = (unsigned short *) p;
433 *c = (s + rel->addend) & 0xffff;
435 break;
437 case R_PPC_ADDR16_HA:
439 unsigned short *c = (unsigned short *) p;
440 ULONG temp = s + rel->addend;
441 *c = temp >> 16;
442 if ((temp & 0x8000) != 0)
443 (*c)++;
445 break;
447 case R_PPC_REL16_LO:
449 unsigned short *c = (unsigned short *) p;
450 *c = (s + rel->addend - (ULONG) p) & 0xffff;
452 break;
454 case R_PPC_REL16_HA:
456 unsigned short *c = (unsigned short *) p;
457 ULONG temp = s + rel->addend - (ULONG) p;
458 *c = temp >> 16;
459 if ((temp & 0x8000) != 0)
460 (*c)++;
462 break;
464 case R_PPC_REL24:
465 *p &= ~0x3fffffc;
466 *p |= (s + rel->addend - (ULONG) p) & 0x3fffffc;
467 break;
469 case R_PPC_REL32:
470 *p = s + rel->addend - (ULONG) p;
471 break;
473 case R_PPC_NONE:
474 break;
476 #elif defined(__arm__)
477 case R_ARM_CALL:
478 case R_ARM_JUMP24:
479 case R_ARM_PC24:
481 /* On ARM the 24 bit offset is shifted by 2 to the right */
482 signed long offset = (*p & 0x00ffffff) << 2;
483 /* If highest bit set, make offset negative */
484 if (offset & 0x02000000)
485 offset -= 0x04000000;
487 offset += s - (uint32_t)p;
489 offset >>= 2;
490 *p &= 0xff000000;
491 *p |= offset & 0x00ffffff;
493 break;
495 case R_ARM_MOVW_ABS_NC:
496 case R_ARM_MOVT_ABS:
498 signed long offset = *p;
499 offset = ((offset & 0xf0000) >> 4) | (offset & 0xfff);
500 offset = (offset ^ 0x8000) - 0x8000;
502 offset += s;
504 if (ELF_R_TYPE(rel->info) == R_ARM_MOVT_ABS)
505 offset >>= 16;
507 *p &= 0xfff0f000;
508 *p |= ((offset & 0xf000) << 4) | (offset & 0x0fff);
510 break;
512 case R_ARM_ABS32:
513 *p += s;
514 break;
516 case R_ARM_NONE:
517 break;
519 #else
520 # error Your architecture is not supported
521 #endif
523 default:
524 D(bug("[ELF Loader] Unrecognized relocation type %d %d\n", i, ELF_R_TYPE(rel->info)));
525 SetIoErr(ERROR_BAD_HUNK);
526 return 0;
530 return 1;
533 BPTR InternalLoadSeg_ELF
535 BPTR file,
536 BPTR table __unused,
537 SIPTR *funcarray,
538 SIPTR *stack __unused,
539 struct DosLibrary *DOSBase
542 struct elfheader eh;
543 struct sheader *sh;
544 struct sheader *symtab_shndx = NULL;
545 BPTR hunks = 0;
546 BPTR *next_hunk_ptr = &hunks;
547 ULONG i;
548 BOOL exec_hunk_seen = FALSE;
549 ULONG int_shnum;
550 ULONG int_shstrndx;
552 /* load and validate ELF header */
553 if (!load_header(file, &eh, funcarray, DOSBase))
554 return 0;
556 if (!load_first_header(file, &eh, funcarray, &int_shnum, &int_shstrndx, DOSBase))
557 return 0;
559 /* load section headers */
560 if (!(sh = load_block(file, eh.shoff, int_shnum * eh.shentsize, funcarray, DOSBase)))
561 return 0;
563 /* load the string table */
564 STRPTR st = NULL;
565 struct sheader *shstr = sh + SHINDEX(int_shstrndx);
567 if (shstr->size != 0)
569 st = MyAlloc(shstr->size, MEMF_ANY | MEMF_CLEAR);
570 read_block(file, shstr->offset, st, shstr->size, funcarray, DOSBase);
573 /* Iterate over the section headers in order to do some stuff... */
574 for (i = 0; i < int_shnum; i++)
577 Load the symbol and string table(s).
579 NOTICE: the ELF standard, at the moment (Nov 2002) explicitely states
580 that only one symbol table per file is allowed. However, it
581 also states that this may change in future... we already handle it.
583 if (sh[i].type == SHT_SYMTAB || sh[i].type == SHT_STRTAB || sh[i].type == SHT_SYMTAB_SHNDX)
585 sh[i].addr = load_block(file, sh[i].offset, sh[i].size, funcarray, DOSBase);
586 if (!sh[i].addr)
587 goto error;
589 if (sh[i].type == SHT_SYMTAB_SHNDX) {
590 if (symtab_shndx == NULL)
591 symtab_shndx = &sh[i];
592 else
593 D(bug("[ELF Loader] file contains multiple symtab shndx tables. only using the first one\n"));
596 else
597 /* Load the section in memory if needed, and make an hunk out of it */
598 if (sh[i].flags & SHF_ALLOC)
600 if (sh[i].size)
602 /* Only allow alignment if this is an executable hunk
603 or if an executable hunk has been loaded already,
604 so to avoid the situation in which a data hunk has its
605 content displaced from the hunk's header in case it's the
606 first hunk (this happens with Keymaps, for instance). */
607 if (sh[i].flags & SHF_EXECINSTR)
608 exec_hunk_seen = TRUE;
610 if (!load_hunk(file, &next_hunk_ptr, &sh[i], funcarray, exec_hunk_seen, DOSBase))
611 goto error;
617 /* Relocate the sections */
618 for (i = 0; i < int_shnum; i++)
620 /* Does this relocation section refer to a hunk? If so, addr must be != 0 */
621 if ((sh[i].type == AROS_ELF_REL) && sh[SHINDEX(sh[i].info)].addr)
623 sh[i].addr = load_block(file, sh[i].offset, sh[i].size, funcarray, DOSBase);
624 if (!sh[i].addr || !relocate(&eh, sh, i, symtab_shndx, DOSBase))
625 goto error;
627 MyFree(sh[i].addr, sh[i].size);
628 sh[i].addr = NULL;
632 /* Everything is loaded now. Register the module at kernel.resource */
633 register_elf(file, hunks, &eh, sh, DOSBase);
634 goto end;
636 error:
638 /* There were some errors, deallocate The hunks */
640 InternalUnLoadSeg(hunks, (VOID_FUNC)funcarray[2]);
641 hunks = 0;
643 end:
645 /* Clear the caches to let the CPU see the new data and instructions */
647 BPTR curr = hunks;
648 while (curr)
650 struct hunk *hunk = BPTR2HUNK(BADDR(curr));
652 CacheClearE(hunk->data, hunk->size, CACRF_ClearD | CACRF_ClearI);
654 curr = hunk->next;
658 /* deallocate the symbol tables */
659 for (i = 0; i < int_shnum; i++)
661 if (((sh[i].type == SHT_SYMTAB) || (sh[i].type == SHT_STRTAB)) && (sh[i].addr != NULL))
662 MyFree(sh[i].addr, sh[i].size);
665 /* Free the string table */
666 MyFree(st, shstr->size);
668 /* Free the section headers */
669 MyFree(sh, int_shnum * eh.shentsize);
671 return hunks;
674 #undef MyRead1
675 #undef MyAlloc
676 #undef MyFree