some fixes to accented characters
[tangerine.git] / rom / dos / internalloadseg_elf64.c
blob9f0e0c0f829d727e9157edcb7d3160474322f627
1 /*
2 Copyright � 1995-2001, The AROS Development Team. All rights reserved.
3 $Id: internalloadseg_elf.c 26730 2007-09-19 20:33:25Z schulz $
5 Desc: Code to dynamically load 64-bit ELF executables
6 Lang: english
7 */
9 #define DEBUG 0
11 #include <exec/memory.h>
12 #include <proto/exec.h>
13 #include <dos/dosasl.h>
14 #include <proto/dos.h>
15 #include <proto/arossupport.h>
16 #include <aros/asmcall.h>
17 #include "internalloadseg.h"
18 #include "dos_intern.h"
20 #include <aros/debug.h>
21 #include <string.h>
22 #include <stddef.h>
24 #include <aros/macros.h>
26 #define SHT_PROGBITS 1
27 #define SHT_SYMTAB 2
28 #define SHT_STRTAB 3
29 #define SHT_RELA 4
30 #define SHT_NOBITS 8
31 #define SHT_REL 9
32 #define SHT_SYMTAB_SHNDX 18
34 #define ET_REL 1
36 #define EM_X86_64 62 /* AMD x86-64 */
38 /* AMD x86-64 relocations. */
39 #define R_X86_64_NONE 0 /* No reloc */
40 #define R_X86_64_64 1 /* Direct 64 bit */
41 #define R_X86_64_PC32 2 /* PC relative 32 bit signed */
42 #define R_X86_64_32 10
43 #define R_X86_64_32S 11
45 #define STT_OBJECT 1
46 #define STT_FUNC 2
48 #define SHN_UNDEF 0
49 #define SHN_LORESERVE 0xff00
50 #define SHN_ABS 0xfff1
51 #define SHN_COMMON 0xfff2
52 #define SHN_XINDEX 0xffff
53 #define SHN_HIRESERVE 0xffff
55 #define SHF_ALLOC (1 << 1)
56 #define SHF_EXECINSTR (1 << 2)
58 #define ELF64_ST_TYPE(i) ((i) & 0x0F)
60 #define EI_VERSION 6
61 #define EV_CURRENT 1
63 #define EI_DATA 5
64 #define ELFDATA2LSB 1
65 #define ELFDATA2MSB 2
67 #define EI_CLASS 4
68 #define ELFCLASS32 1
69 #define ELFCLASS64 2 /* 64-bit objects */
71 #define ELF64_R_SYM(i) (ULONG)((i) >> 32)
72 #define ELF64_R_TYPE(i) (ULONG)((i) & 0xffffffffULL)
73 #define ELF64_R_INFO(sym, type) (((UQUAD)(sym) << 32) + (type))
75 struct elfheader
77 UBYTE ident[16];
78 UWORD type;
79 UWORD machine;
80 ULONG version;
81 APTR entry;
82 UQUAD phoff;
83 UQUAD shoff;
84 ULONG flags;
85 UWORD ehsize;
86 UWORD phentsize;
87 UWORD phnum;
88 UWORD shentsize;
89 UWORD shnum;
90 UWORD shstrndx;
92 /* these are internal, and not part of the header proper. they are wider
93 * versions of shnum and shstrndx for when they don't fit in the header
94 * and we need to get them from the first section header. see
95 * load_header() for details
97 ULONG int_shnum;
98 ULONG int_shstrndx;
101 struct sheader {
102 ULONG name;
103 ULONG type;
104 UQUAD flags;
105 APTR addr;
106 UQUAD offset;
107 UQUAD size;
108 ULONG link;
109 ULONG info;
110 UQUAD addralign;
111 UQUAD entsize;
114 struct symbol {
115 ULONG name; /* Offset of the name string in the string table */
116 UBYTE info; /* What kind of symbol is this ? (global, variable, etc) */
117 UBYTE other; /* undefined */
118 UWORD shindex; /* In which section is the symbol defined ? */
119 UQUAD value; /* Varies; eg. the offset of the symbol in its hunk */
120 UQUAD size; /* How much memory does the symbol occupy */
123 struct relo {
124 UQUAD offset; /* Address of the relocation relative to the section it refers to */
125 UQUAD info; /* Type of the relocation */
126 QUAD addend; /* Constant addend used to compute value */
129 struct hunk
131 ULONG size;
132 BPTR next;
133 char data[0];
134 } __attribute__((packed));
136 #define BPTR2HUNK(bptr) ((struct hunk *)((char *)BADDR(bptr) - offsetof(struct hunk, next)))
137 #define HUNK2BPTR(hunk) MKBADDR(&hunk->next)
139 /* convert section header number to array index */
140 #define SHINDEX(n) \
141 ((n) < SHN_LORESERVE ? (n) : ((n) <= SHN_HIRESERVE ? 0 : (n) - (SHN_HIRESERVE + 1 - SHN_LORESERVE)))
143 /* convert section header array index to section number */
144 #define SHNUM(i) \
145 ((i) < SHN_LORESERVE ? (i) : (i) + (SHN_HIRESERVE + 1 - SHN_LORESERVE))
147 #undef MyRead
148 #undef MyAlloc
149 #undef MyFree
152 #define MyRead(file, buf, size) \
153 AROS_CALL3 \
155 LONG, funcarray[0], \
156 AROS_LCA(BPTR, file, D1), \
157 AROS_LCA(void *, buf, D2), \
158 AROS_LCA(LONG, size, D3), \
159 struct DosLibrary *, DOSBase \
163 #define MyAlloc(size, flags) \
164 AROS_CALL2 \
166 void *, funcarray[1], \
167 AROS_LCA(ULONG, size, D0), \
168 AROS_LCA(ULONG, flags, D1), \
169 struct ExecBase *, SysBase \
173 #define MyFree(addr, size) \
174 AROS_CALL2 \
176 void, funcarray[2], \
177 AROS_LCA(void *, addr, A1), \
178 AROS_LCA(ULONG, size, D0), \
179 struct ExecBase *, SysBase \
182 #if defined (__x86_64__)
184 static int read_block
186 BPTR file,
187 ULONG offset,
188 APTR buffer,
189 ULONG size,
190 SIPTR *funcarray,
191 struct DosLibrary *DOSBase
194 UBYTE *buf = (UBYTE *)buffer;
195 LONG subsize;
197 if (Seek(file, offset, OFFSET_BEGINNING) < 0)
198 return 0;
200 while (size)
202 subsize = MyRead(file, buf, size);
204 if (subsize <= 0)
206 if (subsize == 0)
207 SetIoErr(ERROR_BAD_HUNK);
209 return 0;
212 buf += subsize;
213 size -= subsize;
216 return 1;
219 static void * load_block
221 BPTR file,
222 ULONG offset,
223 ULONG size,
224 SIPTR *funcarray,
225 struct DosLibrary *DOSBase
228 D(bug("[ELF Loader] Load Block\n"));
229 D(bug("[ELF Loader] (size=%d)\n",size));
230 D(bug("[ELF Loader] (funcarray=0x%x)\n",funcarray));
231 D(bug("[ELF Loader] (funcarray[1]=0x%x)\n",funcarray[1]));
232 void *block = MyAlloc(size, MEMF_ANY);
233 if (block)
235 if (read_block(file, offset, block, size, funcarray, DOSBase))
236 return block;
238 MyFree(block, size);
240 else
241 SetIoErr(ERROR_NO_FREE_STORE);
243 return NULL;
246 static int load_header(BPTR file, struct elfheader *eh, SIPTR *funcarray, struct DosLibrary *DOSBase) {
247 if (!read_block(file, 0, eh, offsetof(struct elfheader, int_shnum), funcarray, DOSBase))
248 return 0;
250 if (eh->ident[0] != 0x7f || eh->ident[1] != 'E' ||
251 eh->ident[2] != 'L' || eh->ident[3] != 'F') {
252 D(bug("[ELF Loader] Not an ELF object\n"));
253 SetIoErr(ERROR_NOT_EXECUTABLE);
254 return 0;
256 D(bug("[ELF Loader] ELF object\n"));
258 eh->int_shnum = eh->shnum;
259 eh->int_shstrndx = eh->shstrndx;
261 /* the ELF header only uses 16 bits to store the count of section headers,
262 * so it can't handle more than 65535 headers. if the count is 0, and an
263 * offset is defined, then the real count can be found in the first
264 * section header (which always exists).
266 * similarly, if the string table index is SHN_XINDEX, then the actual
267 * index is found in the first section header also.
269 * see the System V ABI 2001-04-24 draft for more details.
271 if (eh->int_shnum == 0 || eh->int_shstrndx == SHN_XINDEX) {
272 if (eh->shoff == 0) {
273 SetIoErr(ERROR_NOT_EXECUTABLE);
274 return 0;
277 struct sheader sh;
278 if (!read_block(file, eh->shoff, &sh, sizeof(sh), funcarray, DOSBase))
279 return 0;
281 /* wider section header count is in the size field */
282 if (eh->int_shnum == 0)
283 eh->int_shnum = sh.size;
285 /* wider string table index is in the link field */
286 if (eh->int_shstrndx == SHN_XINDEX)
287 eh->int_shstrndx = sh.link;
289 /* sanity, if they're still invalid then this isn't elf */
290 if (eh->int_shnum == 0 || eh->int_shstrndx == SHN_XINDEX) {
291 SetIoErr(ERROR_NOT_EXECUTABLE);
292 return 0;
298 eh->ident[EI_CLASS] != ELFCLASS64 ||
299 eh->ident[EI_VERSION] != EV_CURRENT ||
300 eh->type != ET_REL ||
302 eh->ident[EI_DATA] != ELFDATA2LSB ||
303 eh->machine != EM_X86_64
307 D(bug("[ELF Loader] Object is of wrong type\n"));
308 D(bug("[ELF Loader] EI_CLASS is %d - should be %d\n", eh->ident[EI_CLASS], ELFCLASS64));
309 D(bug("[ELF Loader] EI_VERSION is %d - should be %d\n", eh->ident[EI_VERSION], EV_CURRENT));
310 D(bug("[ELF Loader] type is %d - should be %d\n", eh->type, ET_REL));
311 D(bug("[ELF Loader] EI_DATA is %d - should be %d\n", eh->ident[EI_DATA],ELFDATA2LSB));
312 D(bug("[ELF Loader] machine is %d - should be %d\n", eh->machine, EM_X86_64));
314 SetIoErr(ERROR_NOT_EXECUTABLE);
315 return 0;
318 return 1;
321 static int load_hunk
323 BPTR file,
324 BPTR **next_hunk_ptr,
325 struct sheader *sh,
326 SIPTR *funcarray,
327 BOOL do_align,
328 struct DosLibrary *DOSBase
331 struct hunk *hunk;
332 ULONG hunk_size;
334 D(bug("[dos:ELF64] load_hunk. Do align=%d\n", do_align));
336 if (!sh->size)
337 return 1;
339 D(bug("[dos:ELF64] sh->size=%d, sh->addraligh=%d\n", sh->size, sh->addralign));
341 /* The size of the hunk is the size of the section, plus
342 the size of the hunk structure, plus the size of the alignment (if necessary)*/
343 hunk_size = sh->size + sizeof(struct hunk);
345 if (do_align)
347 hunk_size += sh->addralign;
349 /* Also create space for a trampoline, if necessary */
350 if (sh->flags & SHF_EXECINSTR)
351 hunk_size += sizeof(struct FullJumpVec);
354 hunk = MyAlloc(hunk_size, MEMF_ANY | (sh->type == SHT_NOBITS) ? MEMF_CLEAR : 0);
356 D(bug("[dos:ELF64] hunk=%012p\n", hunk));
358 if (hunk)
360 hunk->next = 0;
361 hunk->size = hunk_size;
363 /* In case we are required to honour alignment, and If this section contains
364 executable code, create a trampoline to its beginning, so that even if the
365 alignment requirements make the actual code go much after the end of the
366 hunk structure, the code can still be reached in the usual way. */
367 if (do_align)
369 if (sh->flags & SHF_EXECINSTR)
371 sh->addr = (char *)AROS_ROUNDUP2
373 (IPTR)hunk->data + sizeof(struct FullJumpVec), sh->addralign
375 __AROS_SET_FULLJMP((struct FullJumpVec *)hunk->data, sh->addr);
377 else
378 sh->addr = (char *)AROS_ROUNDUP2((IPTR)hunk->data, sh->addralign);
380 D(bug("[dos:ELF64] align. %012p -> %012p\n", hunk->data, sh->addr));
382 else
383 sh->addr = hunk->data;
385 (bug("[dos:ELF64] sh->addr = %012lx - %012lx\n", sh->addr, sh->addr + sh->size - 1));
387 /* Link the previous one with the new one */
388 BPTR2HUNK(*next_hunk_ptr)->next = HUNK2BPTR(hunk);
390 /* Update the pointer to the previous one, which is now the current one */
391 *next_hunk_ptr = HUNK2BPTR(hunk);
393 if (sh->type != SHT_NOBITS)
394 return read_block(file, sh->offset, sh->addr, sh->size, funcarray, DOSBase);
396 return 1;
399 SetIoErr(ERROR_NO_FREE_STORE);
401 return 0;
404 static int relocate
406 struct elfheader *eh,
407 struct sheader *sh,
408 ULONG shrel_idx,
409 struct sheader *symtab_shndx,
410 struct DosLibrary *DOSBase
413 struct sheader *shrel = &sh[shrel_idx];
414 struct sheader *shsymtab = &sh[SHINDEX(shrel->link)];
415 struct sheader *toreloc = &sh[SHINDEX(shrel->info)];
417 struct symbol *symtab = (struct symbol *)shsymtab->addr;
418 struct relo *rel = (struct relo *)shrel->addr;
419 char *section = toreloc->addr;
421 /* this happens if the target section has no allocation. that can happen
422 * eg. with a .debug PROGBITS and a .rel.debug section */
423 if (section == NULL)
424 return 1;
426 D(bug("[dos:ELF64] Relocating section at %012p\n", section));
428 ULONG numrel = shrel->size / shrel->entsize;
429 ULONG i;
431 struct symbol *SysBase_sym = NULL;
433 for (i=0; i<numrel; i++, rel++)
435 struct symbol *sym = &symtab[ELF64_R_SYM(rel->info)];
436 ULONG *p = (ULONG *)&section[rel->offset];
437 UQUAD s;
438 ULONG shindex;
440 if (sym->shindex != SHN_XINDEX)
441 shindex = sym->shindex;
443 else {
444 if (symtab_shndx == NULL) {
445 D(bug("[ELF Loader] got symbol with shndx 0xfff, but there's no symtab shndx table\n"));
446 SetIoErr(ERROR_BAD_HUNK);
447 return 0;
449 shindex = ((ULONG *)symtab_shndx->addr)[ELF64_R_SYM(rel->info)];
452 switch (shindex)
455 case SHN_UNDEF:
456 D(bug("[ELF Loader] Undefined symbol '%s' while relocating the section '%s'\n",
457 (STRPTR)sh[SHINDEX(shsymtab->link)].addr + sym->name,
458 (STRPTR)sh[SHINDEX(eh->int_shstrndx)].addr + toreloc->name));
459 SetIoErr(ERROR_BAD_HUNK);
460 return 0;
462 case SHN_COMMON:
463 D(bug("[ELF Loader] COMMON symbol '%s' while relocating the section '%s'\n",
464 (STRPTR)sh[SHINDEX(shsymtab->link)].addr + sym->name,
465 (STRPTR)sh[SHINDEX(eh->int_shstrndx)].addr + toreloc->name));
466 SetIoErr(ERROR_BAD_HUNK);
468 return 0;
470 case SHN_ABS:
471 if (SysBase_sym == NULL)
473 if (strncmp((STRPTR)sh[SHINDEX(shsymtab->link)].addr + sym->name, "SysBase", 8) == 0)
475 SysBase_sym = sym;
476 goto SysBase_yes;
478 else
479 goto SysBase_no;
481 else
482 if (SysBase_sym == sym)
484 SysBase_yes: s = (IPTR)&SysBase;
486 else
487 SysBase_no: s = sym->value;
488 break;
490 default:
491 s = (UQUAD)sh[SHINDEX(shindex)].addr + sym->value;
494 switch (ELF64_R_TYPE(rel->info))
496 #if defined(__x86_64__)
497 /* These weren't tested */
498 case R_X86_64_64: /* 64bit direct/absolute */
499 *(UQUAD *)p = s + rel->addend;
500 break;
502 case R_X86_64_PC32: /* PC relative 32 bit signed */
503 *(ULONG *)p = s + rel->addend - (IPTR) p;
504 break;
506 case R_X86_64_32:
507 *(ULONG *)p = (UQUAD)s + (UQUAD)rel->addend;
508 break;
510 case R_X86_64_32S:
511 *(LONG *)p = (QUAD)s + (QUAD)rel->addend;
512 break;
514 case R_X86_64_NONE: /* No reloc */
515 break;
517 #endif
519 default:
520 D(bug("[ELF Loader] Unrecognized relocation type %d %d\n", i, ELF64_R_TYPE(rel->info)));
521 SetIoErr(ERROR_BAD_HUNK);
522 return 0;
526 return 1;
529 #endif
531 BPTR InternalLoadSeg_ELF64
533 BPTR file,
534 BPTR table __unused,
535 SIPTR *funcarray,
536 SIPTR *stack __unused,
537 struct MinList *seginfos,
538 struct DosLibrary *DOSBase
541 struct elfheader eh;
542 struct sheader *sh;
543 struct sheader *symtab_shndx = NULL;
544 BPTR hunks = 0;
545 BPTR *next_hunk_ptr = &hunks;
546 ULONG i;
547 BOOL exec_hunk_seen = FALSE;
549 #if defined (__x86_64__)
551 /* load and validate ELF header */
552 if (!load_header(file, &eh, funcarray, DOSBase))
553 return 0;
555 /* load section headers */
556 if (!(sh = load_block(file, eh.shoff, eh.int_shnum * eh.shentsize, funcarray, DOSBase)))
557 return 0;
559 /* load the string table */
560 STRPTR st = NULL;
561 struct sheader *shstr = sh + SHINDEX(eh.int_shstrndx);
562 if (shstr->size != 0)
564 st = MyAlloc(shstr->size, MEMF_ANY | MEMF_CLEAR);
565 read_block(file, shstr->offset, st, shstr->size, funcarray, DOSBase);
568 /* Iterate over the section headers in order to do some stuff... */
569 for (i = 0; i < eh.int_shnum; i++)
572 Load the symbol and string table(s).
574 NOTICE: the ELF standard, at the moment (Nov 2002) explicitely states
575 that only one symbol table per file is allowed. However, it
576 also states that this may change in future... we already handle it.
578 if (sh[i].type == SHT_SYMTAB || sh[i].type == SHT_STRTAB || sh[i].type == SHT_SYMTAB_SHNDX)
580 sh[i].addr = load_block(file, sh[i].offset, sh[i].size, funcarray, DOSBase);
581 if (!sh[i].addr)
582 goto error;
584 if (sh[i].type == SHT_SYMTAB_SHNDX) {
585 if (symtab_shndx == NULL)
586 symtab_shndx = &sh[i];
587 else
588 D(bug("[ELF Loader] file contains multiple symtab shndx tables. only using the first one\n"));
591 else
592 /* Load the section in memory if needed, and make an hunk out of it */
593 if (sh[i].flags & SHF_ALLOC)
595 if (sh[i].size)
597 /* Only allow alignment if this is an executable hunk
598 or if an executable hunk has been loaded already,
599 so to avoid the situation in which a data hunk has its
600 content displaced from the hunk's header in case it's the
601 first hunk (this happens with Keymaps, for instance). */
602 if (sh[i].flags & SHF_EXECINSTR)
603 exec_hunk_seen = TRUE;
605 if (!load_hunk(file, &next_hunk_ptr, &sh[i], funcarray, exec_hunk_seen, DOSBase))
606 goto error;
608 if (seginfos)
610 STRPTR name = st + sh[i].name;
611 ULONG size = sizeof(struct seginfo);
612 struct seginfo *si = MyAlloc(size, MEMF_ANY);
614 D(bug("[ELF Loader] seg %s at 0x%x\n", name, sh[i].addr));
616 si->addr = sh[i].addr;
617 size = sizeof(si->name) - 1;
618 strncpy(si->name, name, size);
619 si->name[size] = '\0';
621 ADDTAIL(seginfos, &si->node);
628 /* Relocate the sections */
629 for (i = 0; i < eh.int_shnum; i++)
633 #if defined(__x86_64__)
635 sh[i].type == SHT_RELA &&
637 #endif
639 /* Does this relocation section refer to a hunk? If so, addr must be != 0 */
640 sh[SHINDEX(sh[i].info)].addr
643 sh[i].addr = load_block(file, sh[i].offset, sh[i].size, funcarray, DOSBase);
644 if (!sh[i].addr || !relocate(&eh, sh, i, symtab_shndx, DOSBase))
645 goto error;
647 MyFree(sh[i].addr, sh[i].size);
648 sh[i].addr = NULL;
653 goto end;
655 error:
657 /* There were some errors, deallocate The hunks */
659 InternalUnLoadSeg(hunks, (VOID_FUNC)funcarray[2]);
660 hunks = 0;
662 end:
664 /* Clear the caches to let the CPU see the new data and instructions */
666 BPTR curr = hunks;
667 while (curr)
669 struct hunk *hunk = BPTR2HUNK(curr);
671 CacheClearE(hunk->data, hunk->size, CACRF_ClearD | CACRF_ClearI);
673 curr = hunk->next;
677 /* deallocate the symbol tables */
678 for (i = 0; i < eh.int_shnum; i++)
680 if (((sh[i].type == SHT_SYMTAB) || (sh[i].type == SHT_STRTAB)) && (sh[i].addr != NULL))
681 MyFree(sh[i].addr, sh[i].size);
684 /* Free the string table */
685 MyFree(st, shstr->size);
687 /* Free the section headers */
688 MyFree(sh, eh.int_shnum * eh.shentsize);
690 #else
691 SetIoErr(ERROR_NOT_EXECUTABLE);
692 #endif
694 return hunks;
697 #undef MyRead1
698 #undef MyAlloc
699 #undef MyFree