2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
5 Desc: Code to dynamically load ELF executables
8 1997/12/13: Changed filename to internalloadseg_elf.c
9 Original file was created by digulla.
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>
27 #include <aros/macros.h>
29 #define SHT_PROGBITS 1
35 #define SHT_SYMTAB_SHNDX 18
43 #define EM_X86_64 62 /* AMD x86-64 */
49 /* AMD x86-64 relocations. */
50 #define R_X86_64_NONE 0 /* No reloc */
51 #define R_X86_64_64 1 /* Direct 64 bit */
52 #define R_X86_64_PC32 2 /* PC relative 32 bit signed */
59 #define R_PPC_ADDR32 1
60 #define R_PPC_ADDR16_LO 4
61 #define R_PPC_ADDR16_HA 6
62 #define R_PPC_REL24 10
63 #define R_PPC_REL32 26
64 #define R_PPC_REL16_LO 250
65 #define R_PPC_REL16_HA 252
75 #define SHN_LORESERVE 0xff00
76 #define SHN_ABS 0xfff1
77 #define SHN_COMMON 0xfff2
78 #define SHN_XINDEX 0xffff
79 #define SHN_HIRESERVE 0xffff
81 #define SHF_ALLOC (1 << 1)
82 #define SHF_EXECINSTR (1 << 2)
84 #define ELF32_ST_TYPE(i) ((i) & 0x0F)
95 #define ELFCLASS64 2 /* 64-bit objects */
97 #define ELF32_R_SYM(val) ((val) >> 8)
98 #define ELF32_R_TYPE(val) ((val) & 0xff)
99 #define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff))
119 /* these are internal, and not part of the header proper. they are wider
120 * versions of shnum and shstrndx for when they don't fit in the header
121 * and we need to get them from the first section header. see
122 * load_header() for details
144 ULONG name
; /* Offset of the name string in the string table */
145 ULONG value
; /* Varies; eg. the offset of the symbol in its hunk */
146 ULONG size
; /* How much memory does the symbol occupy */
147 UBYTE info
; /* What kind of symbol is this ? (global, variable, etc) */
148 UBYTE other
; /* undefined */
149 UWORD shindex
; /* In which section is the symbol defined ? */
154 ULONG offset
; /* Address of the relocation relative to the section it refers to */
155 ULONG info
; /* Type of the relocation */
156 #if defined(__mc68000__) || defined (__x86_64__) || defined (__ppc__) || defined (__powerpc__) || defined(__arm__)
157 LONG addend
; /* Constant addend used to compute value */
166 } __attribute__((packed
));
168 #define BPTR2HUNK(bptr) ((struct hunk *)((char *)BADDR(bptr) - offsetof(struct hunk, next)))
169 #define HUNK2BPTR(hunk) MKBADDR(&hunk->next)
171 /* convert section header number to array index */
173 ((n) < SHN_LORESERVE ? (n) : ((n) <= SHN_HIRESERVE ? 0 : (n) - (SHN_HIRESERVE + 1 - SHN_LORESERVE)))
175 /* convert section header array index to section number */
177 ((i) < SHN_LORESERVE ? (i) : (i) + (SHN_HIRESERVE + 1 - SHN_LORESERVE))
184 #define MyRead(file, buf, size) \
187 LONG, funcarray[0], \
188 AROS_LCA(BPTR, file, D1), \
189 AROS_LCA(void *, buf, D2), \
190 AROS_LCA(LONG, size, D3), \
191 struct DosLibrary *, DOSBase \
195 #define MyAlloc(size, flags) \
198 void *, funcarray[1], \
199 AROS_LCA(ULONG, size, D0), \
200 AROS_LCA(ULONG, flags, D1), \
201 struct ExecBase *, SysBase \
205 #define MyFree(addr, size) \
208 void, funcarray[2], \
209 AROS_LCA(void *, addr, A1), \
210 AROS_LCA(ULONG, size, D0), \
211 struct ExecBase *, SysBase \
214 static int read_block
221 struct DosLibrary
*DOSBase
224 UBYTE
*buf
= (UBYTE
*)buffer
;
227 if (Seek(file
, offset
, OFFSET_BEGINNING
) < 0)
232 subsize
= MyRead(file
, buf
, size
);
237 SetIoErr(ERROR_BAD_HUNK
);
249 static void * load_block
255 struct DosLibrary
*DOSBase
258 D(bug("[ELF Loader] Load Block\n"));
259 D(bug("[ELF Loader] (size=%d)\n",size
));
260 D(bug("[ELF Loader] (funcarray=0x%x)\n",funcarray
));
261 D(bug("[ELF Loader] (funcarray[1]=0x%x)\n",funcarray
[1]));
262 void *block
= MyAlloc(size
, MEMF_ANY
);
265 if (read_block(file
, offset
, block
, size
, funcarray
, DOSBase
))
271 SetIoErr(ERROR_NO_FREE_STORE
);
276 static int load_header(BPTR file
, struct elfheader
*eh
, SIPTR
*funcarray
, struct DosLibrary
*DOSBase
) {
277 if (!read_block(file
, 0, eh
, offsetof(struct elfheader
, int_shnum
), funcarray
, DOSBase
))
280 if (eh
->ident
[0] != 0x7f || eh
->ident
[1] != 'E' ||
281 eh
->ident
[2] != 'L' || eh
->ident
[3] != 'F') {
282 D(bug("[ELF Loader] Not an ELF object\n"));
283 SetIoErr(ERROR_NOT_EXECUTABLE
);
286 D(bug("[ELF Loader] ELF object\n"));
288 eh
->int_shnum
= eh
->shnum
;
289 eh
->int_shstrndx
= eh
->shstrndx
;
291 /* the ELF header only uses 16 bits to store the count of section headers,
292 * so it can't handle more than 65535 headers. if the count is 0, and an
293 * offset is defined, then the real count can be found in the first
294 * section header (which always exists).
296 * similarly, if the string table index is SHN_XINDEX, then the actual
297 * index is found in the first section header also.
299 * see the System V ABI 2001-04-24 draft for more details.
301 if (eh
->int_shnum
== 0 || eh
->int_shstrndx
== SHN_XINDEX
) {
302 if (eh
->shoff
== 0) {
303 SetIoErr(ERROR_NOT_EXECUTABLE
);
308 if (!read_block(file
, eh
->shoff
, &sh
, sizeof(sh
), funcarray
, DOSBase
))
311 /* wider section header count is in the size field */
312 if (eh
->int_shnum
== 0)
313 eh
->int_shnum
= sh
.size
;
315 /* wider string table index is in the link field */
316 if (eh
->int_shstrndx
== SHN_XINDEX
)
317 eh
->int_shstrndx
= sh
.link
;
319 /* sanity, if they're still invalid then this isn't elf */
320 if (eh
->int_shnum
== 0 || eh
->int_shstrndx
== SHN_XINDEX
) {
321 SetIoErr(ERROR_NOT_EXECUTABLE
);
328 eh
->ident
[EI_CLASS
] != ELFCLASS32
||
329 eh
->ident
[EI_VERSION
] != EV_CURRENT
||
330 eh
->type
!= ET_REL
||
332 #if defined(__i386__)
333 eh
->ident
[EI_DATA
] != ELFDATA2LSB
||
334 eh
->machine
!= EM_386
336 #elif defined(__x86_64__)
337 eh
->ident
[EI_DATA
] != ELFDATA2LSB
||
338 eh
->machine
!= EM_X86_64
340 #elif defined(__mc68000__)
341 eh
->ident
[EI_DATA
] != ELFDATA2MSB
||
342 eh
->machine
!= EM_68K
344 #elif defined(__ppc__) || defined(__powerpc__)
345 eh
->ident
[EI_DATA
] != ELFDATA2MSB
||
346 eh
->machine
!= EM_PPC
348 #elif defined(__arm__)
349 eh
->ident
[EI_DATA
] != ELFDATA2LSB
||
350 eh
->machine
!= EM_ARM
351 #warning ARM has not been tested, yet!
354 # error Your architecture is not supported
358 D(bug("[ELF Loader] Object is of wrong type\n"));
359 #if defined(__x86_64__)
360 D(bug("[ELF Loader] EI_CLASS is %d - should be %d\n", eh
->ident
[EI_CLASS
], ELFCLASS64
));
362 D(bug("[ELF Loader] EI_CLASS is %d - should be %d\n", eh
->ident
[EI_CLASS
], ELFCLASS32
));
364 D(bug("[ELF Loader] EI_VERSION is %d - should be %d\n", eh
->ident
[EI_VERSION
], EV_CURRENT
));
365 D(bug("[ELF Loader] type is %d - should be %d\n", eh
->type
, ET_REL
));
366 #if defined (__i386__)
367 D(bug("[ELF Loader] EI_DATA is %d - should be %d\n", eh
->ident
[EI_DATA
],ELFDATA2LSB
));
368 #elif defined (__mc68000__)
369 D(bug("[ELF Loader] EI_DATA is %d - should be %d\n", eh
->ident
[EI_DATA
],ELFDATA2MSB
));
370 #elif defined(__ppc__) || defined(__powerpc__)
371 D(bug("[ELF Loader] EI_DATA is %d - should be %d\n", eh
->ident
[EI_DATA
],ELFDATA2MSB
));
372 #elif defined (__arm__)
373 D(bug("[ELF Loader] EI_DATA is %d - should be %d\n", eh
->ident
[EI_DATA
],ELFDATA2MSB
));
376 #if defined (__i386__)
377 D(bug("[ELF Loader] machine is %d - should be %d\n", eh
->machine
, EM_386
));
378 #elif defined(__mc68000__)
379 D(bug("[ELF Loader] machine is %d - should be %d\n", eh
->machine
, EM_68K
));
380 #elif defined(__ppc__) || defined(__powerpc__)
381 D(bug("[ELF Loader] machine is %d - should be %d\n", eh
->machine
, EM_PPC
));
382 #elif defined(__arm__)
383 D(bug("[ELF Loader] machine is %d - should be %d\n", eh
->machine
, EM_ARM
));
386 SetIoErr(ERROR_NOT_EXECUTABLE
);
396 BPTR
**next_hunk_ptr
,
400 struct DosLibrary
*DOSBase
409 /* The size of the hunk is the size of the section, plus
410 the size of the hunk structure, plus the size of the alignment (if necessary)*/
411 hunk_size
= sh
->size
+ sizeof(struct hunk
);
415 hunk_size
+= sh
->addralign
;
417 /* Also create space for a trampoline, if necessary */
418 if (sh
->flags
& SHF_EXECINSTR
)
419 hunk_size
+= sizeof(struct FullJumpVec
);
422 hunk
= MyAlloc(hunk_size
, MEMF_ANY
| (sh
->type
== SHT_NOBITS
) ? MEMF_CLEAR
: 0);
426 hunk
->size
= hunk_size
;
428 /* In case we are required to honour alignment, and If this section contains
429 executable code, create a trampoline to its beginning, so that even if the
430 alignment requirements make the actual code go much after the end of the
431 hunk structure, the code can still be reached in the usual way. */
434 if (sh
->flags
& SHF_EXECINSTR
)
436 sh
->addr
= (char *)AROS_ROUNDUP2
438 (ULONG
)hunk
->data
+ sizeof(struct FullJumpVec
), sh
->addralign
440 __AROS_SET_FULLJMP((struct FullJumpVec
*)hunk
->data
, sh
->addr
);
443 sh
->addr
= (char *)AROS_ROUNDUP2((ULONG
)hunk
->data
, sh
->addralign
);
446 sh
->addr
= hunk
->data
;
448 /* Link the previous one with the new one */
449 BPTR2HUNK(*next_hunk_ptr
)->next
= HUNK2BPTR(hunk
);
451 D(bug("[dos] hunk @ %p\n", sh
->addr
));
453 /* Update the pointer to the previous one, which is now the current one */
454 *next_hunk_ptr
= HUNK2BPTR(hunk
);
456 if (sh
->type
!= SHT_NOBITS
)
457 return read_block(file
, sh
->offset
, sh
->addr
, sh
->size
, funcarray
, DOSBase
);
463 SetIoErr(ERROR_NO_FREE_STORE
);
470 struct elfheader
*eh
,
473 struct sheader
*symtab_shndx
,
474 struct DosLibrary
*DOSBase
477 struct sheader
*shrel
= &sh
[shrel_idx
];
478 struct sheader
*shsymtab
= &sh
[SHINDEX(shrel
->link
)];
479 struct sheader
*toreloc
= &sh
[SHINDEX(shrel
->info
)];
481 struct symbol
*symtab
= (struct symbol
*)shsymtab
->addr
;
482 struct relo
*rel
= (struct relo
*)shrel
->addr
;
483 char *section
= toreloc
->addr
;
485 /* this happens if the target section has no allocation. that can happen
486 * eg. with a .debug PROGBITS and a .rel.debug section */
490 ULONG numrel
= shrel
->size
/ shrel
->entsize
;
493 struct symbol
*SysBase_sym
= NULL
;
495 for (i
=0; i
<numrel
; i
++, rel
++)
497 struct symbol
*sym
= &symtab
[ELF32_R_SYM(rel
->info
)];
498 ULONG
*p
= (ULONG
*)§ion
[rel
->offset
];
502 if (sym
->shindex
!= SHN_XINDEX
)
503 shindex
= sym
->shindex
;
506 if (symtab_shndx
== NULL
) {
507 D(bug("[ELF Loader] got symbol with shndx 0xfff, but there's no symtab shndx table\n"));
508 SetIoErr(ERROR_BAD_HUNK
);
511 shindex
= ((ULONG
*)symtab_shndx
->addr
)[ELF32_R_SYM(rel
->info
)];
518 D(bug("[ELF Loader] Undefined symbol '%s' while relocating the section '%s'\n",
519 (STRPTR
)sh
[SHINDEX(shsymtab
->link
)].addr
+ sym
->name
,
520 (STRPTR
)sh
[SHINDEX(eh
->int_shstrndx
)].addr
+ toreloc
->name
));
521 SetIoErr(ERROR_BAD_HUNK
);
525 D(bug("[ELF Loader] COMMON symbol '%s' while relocating the section '%s'\n",
526 (STRPTR
)sh
[SHINDEX(shsymtab
->link
)].addr
+ sym
->name
,
527 (STRPTR
)sh
[SHINDEX(eh
->int_shstrndx
)].addr
+ toreloc
->name
));
528 SetIoErr(ERROR_BAD_HUNK
);
533 if (SysBase_sym
== NULL
)
535 if (strncmp((STRPTR
)sh
[SHINDEX(shsymtab
->link
)].addr
+ sym
->name
, "SysBase", 8) == 0)
544 if (SysBase_sym
== sym
)
546 SysBase_yes
: s
= (ULONG
)&SysBase
;
549 SysBase_no
: s
= sym
->value
;
553 s
= (ULONG
)sh
[SHINDEX(shindex
)].addr
+ sym
->value
;
556 switch (ELF32_R_TYPE(rel
->info
))
558 #if defined(__i386__)
560 case R_386_32
: /* 32bit absolute */
564 case R_386_PC32
: /* 32bit PC relative */
571 #elif defined(__x86_64__)
572 /* These weren't tested */
573 case R_X86_64_64
: /* 64bit direct/absolute */
574 *p
= s
+ rel
->addend
;
577 case R_X86_64_PC32
: /* PC relative 32 bit signed */
578 *p
= s
+ rel
->addend
- (ULONG
)p
;
581 case R_X86_64_NONE
: /* No reloc */
584 #elif defined(__mc68000__)
587 *p
= s
+ rel
->addend
;
591 *p
= s
+ rel
->addend
- (ULONG
)p
;
597 #elif defined(__ppc__) || defined(__powerpc__)
600 *p
= s
+ rel
->addend
;
603 case R_PPC_ADDR16_LO
:
605 unsigned short *c
= (unsigned short *) p
;
606 *c
= (s
+ rel
->addend
) & 0xffff;
610 case R_PPC_ADDR16_HA
:
612 unsigned short *c
= (unsigned short *) p
;
613 ULONG temp
= s
+ rel
->addend
;
615 if ((temp
& 0x8000) != 0)
622 unsigned short *c
= (unsigned short *) p
;
623 *c
= (s
+ rel
->addend
- (ULONG
) p
) & 0xffff;
629 unsigned short *c
= (unsigned short *) p
;
630 ULONG temp
= s
+ rel
->addend
- (ULONG
) p
;
632 if ((temp
& 0x8000) != 0)
639 *p
|= (s
+ rel
->addend
- (ULONG
) p
) & 0x3fffffc;
643 *p
= s
+ rel
->addend
- (ULONG
) p
;
649 #elif defined(__arm__)
652 * This has not been tested. Taken from ARMELF.pdf
653 * from arm.com page 33ff.
656 *p
= s
+ rel
->addend
- (ULONG
)p
;
660 *p
= s
+ rel
->addend
;
667 # error Your architecture is not supported
671 D(bug("[ELF Loader] Unrecognized relocation type %d %d\n", i
, ELF32_R_TYPE(rel
->info
)));
672 SetIoErr(ERROR_BAD_HUNK
);
680 BPTR InternalLoadSeg_ELF
685 SIPTR
*stack __unused
,
686 struct MinList
*seginfos
,
687 struct DosLibrary
*DOSBase
692 struct sheader
*symtab_shndx
= NULL
;
694 BPTR
*next_hunk_ptr
= MKBADDR(&hunks
);
696 BOOL exec_hunk_seen
= FALSE
;
698 /* load and validate ELF header */
699 if (!load_header(file
, &eh
, funcarray
, DOSBase
))
702 /* load section headers */
703 if (!(sh
= load_block(file
, eh
.shoff
, eh
.int_shnum
* eh
.shentsize
, funcarray
, DOSBase
)))
706 /* load the string table */
708 struct sheader
*shstr
= sh
+ SHINDEX(eh
.int_shstrndx
);
709 if (shstr
->size
!= 0)
711 st
= MyAlloc(shstr
->size
, MEMF_ANY
| MEMF_CLEAR
);
712 read_block(file
, shstr
->offset
, st
, shstr
->size
, funcarray
, DOSBase
);
715 /* Iterate over the section headers in order to do some stuff... */
716 for (i
= 0; i
< eh
.int_shnum
; i
++)
719 Load the symbol and string table(s).
721 NOTICE: the ELF standard, at the moment (Nov 2002) explicitely states
722 that only one symbol table per file is allowed. However, it
723 also states that this may change in future... we already handle it.
725 if (sh
[i
].type
== SHT_SYMTAB
|| sh
[i
].type
== SHT_STRTAB
|| sh
[i
].type
== SHT_SYMTAB_SHNDX
)
727 sh
[i
].addr
= load_block(file
, sh
[i
].offset
, sh
[i
].size
, funcarray
, DOSBase
);
731 if (sh
[i
].type
== SHT_SYMTAB_SHNDX
) {
732 if (symtab_shndx
== NULL
)
733 symtab_shndx
= &sh
[i
];
735 D(bug("[ELF Loader] file contains multiple symtab shndx tables. only using the first one\n"));
739 /* Load the section in memory if needed, and make an hunk out of it */
740 if (sh
[i
].flags
& SHF_ALLOC
)
744 /* Only allow alignment if this is an executable hunk
745 or if an executable hunk has been loaded already,
746 so to avoid the situation in which a data hunk has its
747 content displaced from the hunk's header in case it's the
748 first hunk (this happens with Keymaps, for instance). */
749 if (sh
[i
].flags
& SHF_EXECINSTR
)
750 exec_hunk_seen
= TRUE
;
752 if (!load_hunk(file
, &next_hunk_ptr
, &sh
[i
], funcarray
, exec_hunk_seen
, DOSBase
))
757 STRPTR name
= st
+ sh
[i
].name
;
758 ULONG size
= sizeof(struct seginfo
);
759 struct seginfo
*si
= MyAlloc(size
, MEMF_ANY
);
761 D(bug("[ELF Loader] seg %s at 0x%x\n", name
, sh
[i
].addr
));
763 si
->addr
= sh
[i
].addr
;
764 size
= sizeof(si
->name
) - 1;
765 strncpy(si
->name
, name
, size
);
766 si
->name
[size
] = '\0';
768 ADDTAIL(seginfos
, &si
->node
);
775 /* Relocate the sections */
776 for (i
= 0; i
< eh
.int_shnum
; i
++)
780 #if defined(__i386__)
782 sh
[i
].type
== SHT_REL
&&
784 #elif defined(__x86_64__)
786 sh
[i
].type
== SHT_RELA
&&
788 #elif defined(__mc68000__)
790 sh
[i
].type
== SHT_RELA
&&
792 #elif defined(__ppc__) || defined(__powerpc__)
794 sh
[i
].type
== SHT_RELA
&&
796 #elif defined(__arm__)
797 #warning Missing code for ARM
801 # error Your architecture is not supported
804 /* Does this relocation section refer to a hunk? If so, addr must be != 0 */
805 sh
[SHINDEX(sh
[i
].info
)].addr
808 sh
[i
].addr
= load_block(file
, sh
[i
].offset
, sh
[i
].size
, funcarray
, DOSBase
);
809 if (!sh
[i
].addr
|| !relocate(&eh
, sh
, i
, symtab_shndx
, DOSBase
))
812 MyFree(sh
[i
].addr
, sh
[i
].size
);
822 /* There were some errors, deallocate The hunks */
824 InternalUnLoadSeg(hunks
, (VOID_FUNC
)funcarray
[2]);
829 /* Clear the caches to let the CPU see the new data and instructions */
834 struct hunk
*hunk
= BPTR2HUNK(curr
);
836 CacheClearE(hunk
->data
, hunk
->size
, CACRF_ClearD
| CACRF_ClearI
);
842 /* deallocate the symbol tables */
843 for (i
= 0; i
< eh
.int_shnum
; i
++)
845 if (((sh
[i
].type
== SHT_SYMTAB
) || (sh
[i
].type
== SHT_STRTAB
)) && (sh
[i
].addr
!= NULL
))
846 MyFree(sh
[i
].addr
, sh
[i
].size
);
849 /* Free the string table */
850 MyFree(st
, shstr
->size
);
852 /* Free the section headers */
853 MyFree(sh
, eh
.int_shnum
* eh
.shentsize
);