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
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>
24 #include <aros/macros.h>
26 #define SHT_PROGBITS 1
32 #define SHT_SYMTAB_SHNDX 18
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
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)
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))
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
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 */
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 */
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 */
141 ((n) < SHN_LORESERVE ? (n) : ((n) <= SHN_HIRESERVE ? 0 : (n) - (SHN_HIRESERVE + 1 - SHN_LORESERVE)))
143 /* convert section header array index to section number */
145 ((i) < SHN_LORESERVE ? (i) : (i) + (SHN_HIRESERVE + 1 - SHN_LORESERVE))
152 #define MyRead(file, buf, size) \
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) \
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) \
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
191 struct DosLibrary
*DOSBase
194 UBYTE
*buf
= (UBYTE
*)buffer
;
197 if (Seek(file
, offset
, OFFSET_BEGINNING
) < 0)
202 subsize
= MyRead(file
, buf
, size
);
207 SetIoErr(ERROR_BAD_HUNK
);
219 static void * load_block
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
);
235 if (read_block(file
, offset
, block
, size
, funcarray
, DOSBase
))
241 SetIoErr(ERROR_NO_FREE_STORE
);
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
))
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
);
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
);
278 if (!read_block(file
, eh
->shoff
, &sh
, sizeof(sh
), funcarray
, DOSBase
))
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
);
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
);
324 BPTR
**next_hunk_ptr
,
328 struct DosLibrary
*DOSBase
334 D(bug("[dos:ELF64] load_hunk. Do align=%d\n", do_align
));
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
);
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
));
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. */
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
);
378 sh
->addr
= (char *)AROS_ROUNDUP2((IPTR
)hunk
->data
, sh
->addralign
);
380 D(bug("[dos:ELF64] align. %012p -> %012p\n", hunk
->data
, sh
->addr
));
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
);
399 SetIoErr(ERROR_NO_FREE_STORE
);
406 struct elfheader
*eh
,
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 */
426 D(bug("[dos:ELF64] Relocating section at %012p\n", section
));
428 ULONG numrel
= shrel
->size
/ shrel
->entsize
;
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
*)§ion
[rel
->offset
];
440 if (sym
->shindex
!= SHN_XINDEX
)
441 shindex
= sym
->shindex
;
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
);
449 shindex
= ((ULONG
*)symtab_shndx
->addr
)[ELF64_R_SYM(rel
->info
)];
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
);
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
);
471 if (SysBase_sym
== NULL
)
473 if (strncmp((STRPTR
)sh
[SHINDEX(shsymtab
->link
)].addr
+ sym
->name
, "SysBase", 8) == 0)
482 if (SysBase_sym
== sym
)
484 SysBase_yes
: s
= (IPTR
)&SysBase
;
487 SysBase_no
: s
= sym
->value
;
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
;
502 case R_X86_64_PC32
: /* PC relative 32 bit signed */
503 *(ULONG
*)p
= s
+ rel
->addend
- (IPTR
) p
;
507 *(ULONG
*)p
= (UQUAD
)s
+ (UQUAD
)rel
->addend
;
511 *(LONG
*)p
= (QUAD
)s
+ (QUAD
)rel
->addend
;
514 case R_X86_64_NONE
: /* No reloc */
520 D(bug("[ELF Loader] Unrecognized relocation type %d %d\n", i
, ELF64_R_TYPE(rel
->info
)));
521 SetIoErr(ERROR_BAD_HUNK
);
531 BPTR InternalLoadSeg_ELF64
536 SIPTR
*stack __unused
,
537 struct MinList
*seginfos
,
538 struct DosLibrary
*DOSBase
543 struct sheader
*symtab_shndx
= NULL
;
545 BPTR
*next_hunk_ptr
= &hunks
;
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
))
555 /* load section headers */
556 if (!(sh
= load_block(file
, eh
.shoff
, eh
.int_shnum
* eh
.shentsize
, funcarray
, DOSBase
)))
559 /* load the string table */
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
);
584 if (sh
[i
].type
== SHT_SYMTAB_SHNDX
) {
585 if (symtab_shndx
== NULL
)
586 symtab_shndx
= &sh
[i
];
588 D(bug("[ELF Loader] file contains multiple symtab shndx tables. only using the first one\n"));
592 /* Load the section in memory if needed, and make an hunk out of it */
593 if (sh
[i
].flags
& SHF_ALLOC
)
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
))
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
&&
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
))
647 MyFree(sh
[i
].addr
, sh
[i
].size
);
657 /* There were some errors, deallocate The hunks */
659 InternalUnLoadSeg(hunks
, (VOID_FUNC
)funcarray
[2]);
664 /* Clear the caches to let the CPU see the new data and instructions */
669 struct hunk
*hunk
= BPTR2HUNK(curr
);
671 CacheClearE(hunk
->data
, hunk
->size
, CACRF_ClearD
| CACRF_ClearI
);
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
);
691 SetIoErr(ERROR_NOT_EXECUTABLE
);