2 Copyright © 1995-2001, 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
42 #define EM_X86_64 62 /* AMD x86-64 */
48 /* AMD x86-64 relocations. */
49 #define R_X86_64_NONE 0 /* No reloc */
50 #define R_X86_64_64 1 /* Direct 64 bit */
51 #define R_X86_64_PC32 2 /* PC relative 32 bit signed */
58 #define R_PPC_ADDR32 1
59 #define R_PPC_ADDR16_LO 4
60 #define R_PPC_ADDR16_HA 6
61 #define R_PPC_REL24 10
62 #define R_PPC_REL32 26
71 #define SHN_ABS 0xfff1
72 #define SHN_COMMON 0xfff2
75 #define SHF_ALLOC (1 << 1)
76 #define SHF_EXECINSTR (1 << 2)
78 #define ELF32_ST_TYPE(i) ((i) & 0x0F)
89 #define ELFCLASS64 2 /* 64-bit objects */
91 #define ELF32_R_SYM(val) ((val) >> 8)
92 #define ELF32_R_TYPE(val) ((val) & 0xff)
93 #define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff))
130 ULONG name
; /* Offset of the name string in the string table */
131 ULONG value
; /* Varies; eg. the offset of the symbol in its hunk */
132 ULONG size
; /* How much memory does the symbol occupy */
133 UBYTE info
; /* What kind of symbol is this ? (global, variable, etc) */
134 UBYTE other
; /* undefined */
135 UWORD shindex
; /* In which section is the symbol defined ? */
140 ULONG offset
; /* Address of the relocation relative to the section it refers to */
141 ULONG info
; /* Type of the relocation */
142 #if defined(__mc68000__) || defined (__x86_64__) || defined (__ppc__) || defined (__powerpc__) || defined(__arm__)
143 LONG addend
; /* Constant addend used to compute value */
152 } __attribute__((packed
));
154 #define BPTR2HUNK(bptr) ((struct hunk *)((char *)BADDR(bptr) - offsetof(struct hunk, next)))
155 #define HUNK2BPTR(hunk) MKBADDR(&hunk->next)
162 #define MyRead(file, buf, size) \
165 LONG, funcarray[0], \
166 AROS_LCA(BPTR, file, D1), \
167 AROS_LCA(void *, buf, D2), \
168 AROS_LCA(LONG, size, D3), \
169 struct DosLibrary *, DOSBase \
173 #define MyAlloc(size, flags) \
176 void *, funcarray[1], \
177 AROS_LCA(ULONG, size, D0), \
178 AROS_LCA(ULONG, flags, D1), \
179 struct ExecBase *, SysBase \
183 #define MyFree(addr, size) \
186 void, funcarray[2], \
187 AROS_LCA(void *, addr, A1), \
188 AROS_LCA(ULONG, size, D0), \
189 struct ExecBase *, SysBase \
192 static int read_block
199 struct DosLibrary
*DOSBase
202 UBYTE
*buf
= (UBYTE
*)buffer
;
205 if (Seek(file
, offset
, OFFSET_BEGINNING
) < 0)
210 subsize
= MyRead(file
, buf
, size
);
215 SetIoErr(ERROR_BAD_HUNK
);
227 static void * load_block
233 struct DosLibrary
*DOSBase
236 void *block
= MyAlloc(size
, MEMF_ANY
);
239 if (read_block(file
, offset
, block
, size
, funcarray
, DOSBase
))
245 SetIoErr(ERROR_NO_FREE_STORE
);
250 static int check_header(struct elfheader
*eh
, struct DosLibrary
*DOSBase
)
254 eh
->ident
[0] != 0x7f ||
255 eh
->ident
[1] != 'E' ||
256 eh
->ident
[2] != 'L' ||
260 D(bug("[ELF Loader] Not an ELF object\n"));
261 SetIoErr(ERROR_NOT_EXECUTABLE
);
267 eh
->ident
[EI_CLASS
] != ELFCLASS32
||
268 eh
->ident
[EI_VERSION
] != EV_CURRENT
||
269 eh
->type
!= ET_REL
||
271 #if defined(__i386__)
273 eh
->ident
[EI_DATA
] != ELFDATA2LSB
||
274 eh
->machine
!= EM_386
276 #elif defined(__x86_64__)
277 eh
->ident
[EI_DATA
] != ELFDATA2LSB
||
278 eh
->machine
!= EM_X86_64
280 #elif defined(__mc68000__)
282 eh
->ident
[EI_DATA
] != ELFDATA2MSB
||
283 eh
->machine
!= EM_68K
284 #elif defined(__ppc__) || defined(__powerpc__)
285 eh
->ident
[EI_DATA
] != ELFDATA2MSB
||
286 eh
->machine
!= EM_PPC
287 #elif defined(__arm__)
288 eh
->ident
[EI_DATA
] != ELFDATA2LSB
||
289 eh
->machine
!= EM_ARM
290 #warning ARM has not been tested, yet!
292 # error Your architecture is not supported
296 D(bug("[ELF Loader] Object is of wrong type\n"));
297 D(bug("[ELF Loader] EI_CLASS is %d - should be %d\n", eh
->ident
[EI_CLASS
], ELFCLASS32
));
298 D(bug("[ELF Loader] EI_VERSION is %d - should be %d\n", eh
->ident
[EI_VERSION
], EV_CURRENT
));
299 D(bug("[ELF Loader] type is %d - should be %d\n", eh
->type
, ET_REL
));
300 #if defined (__i386__)
301 D(bug("[ELF Loader] EI_DATA is %d - should be %d\n", eh
->ident
[EI_DATA
],ELFDATA2LSB
));
302 #elif defined (__mc68000__)
303 D(bug("[ELF Loader] EI_DATA is %d - should be %d\n", eh
->ident
[EI_DATA
],ELFDATA2MSB
));
304 #elif defined(__ppc__) || defined(__powerpc__)
305 D(bug("[ELF Loader] EI_DATA is %d - should be %d\n", eh
->ident
[EI_DATA
],ELFDATA2MSB
));
306 #elif defined (__arm__)
307 D(bug("[ELF Loader] EI_DATA is %d - should be %d\n", eh
->ident
[EI_DATA
],ELFDATA2MSB
));
310 #if defined (__i386__)
311 D(bug("[ELF Loader] machine is %d - should be %d\n", eh
->machine
, EM_386
));
312 #elif defined(__mc68000__)
313 D(bug("[ELF Loader] machine is %d - should be %d\n", eh
->machine
, EM_68K
));
314 #elif defined(__ppc__) || defined(__powerpc__)
315 D(bug("[ELF Loader] machine is %d - should be %d\n", eh
->machine
, EM_PPC
));
316 #elif defined(__arm__)
317 D(bug("[ELF Loader] machine is %d - should be %d\n", eh
->machine
, EM_ARM
));
320 SetIoErr(ERROR_NOT_EXECUTABLE
);
330 BPTR
**next_hunk_ptr
,
334 struct DosLibrary
*DOSBase
343 /* The size of the hunk is the size of the section, plus
344 the size of the hunk structure, plus the size of the alignment (if necessary)*/
345 hunk_size
= sh
->size
+ sizeof(struct hunk
);
349 hunk_size
+= sh
->addralign
;
351 /* Also create space for a trampoline, if necessary */
352 if (sh
->flags
& SHF_EXECINSTR
)
353 hunk_size
+= sizeof(struct FullJumpVec
);
356 hunk
= MyAlloc(hunk_size
, MEMF_ANY
| (sh
->type
== SHT_NOBITS
) ? MEMF_CLEAR
: 0);
360 hunk
->size
= hunk_size
;
362 /* In case we are required to honour alignment, and If this section contains
363 executable code, create a trampoline to its beginning, so that even if the
364 alignment requirements make the actual code go much after the end of the
365 hunk structure, the code can still be reached in the usual way. */
368 if (sh
->flags
& SHF_EXECINSTR
)
370 sh
->addr
= (char *)AROS_ROUNDUP2
372 (ULONG
)hunk
->data
+ sizeof(struct FullJumpVec
), sh
->addralign
374 __AROS_SET_FULLJMP((struct FullJumpVec
*)hunk
->data
, sh
->addr
);
377 sh
->addr
= (char *)AROS_ROUNDUP2((ULONG
)hunk
->data
, sh
->addralign
);
380 sh
->addr
= hunk
->data
;
382 /* Link the previous one with the new one */
383 BPTR2HUNK(*next_hunk_ptr
)->next
= HUNK2BPTR(hunk
);
385 /* Update the pointer to the previous one, which is now the current one */
386 *next_hunk_ptr
= HUNK2BPTR(hunk
);
388 if (sh
->type
!= SHT_NOBITS
)
389 return read_block(file
, sh
->offset
, sh
->addr
, sh
->size
, funcarray
, DOSBase
);
395 SetIoErr(ERROR_NO_FREE_STORE
);
402 struct elfheader
*eh
,
405 struct DosLibrary
*DOSBase
408 struct sheader
*shrel
= &sh
[shrel_idx
];
409 struct sheader
*shsymtab
= &sh
[shrel
->link
];
410 struct sheader
*toreloc
= &sh
[shrel
->info
];
412 struct symbol
*symtab
= (struct symbol
*)shsymtab
->addr
;
413 struct relo
*rel
= (struct relo
*)shrel
->addr
;
414 char *section
= toreloc
->addr
;
416 ULONG numrel
= shrel
->size
/ shrel
->entsize
;
419 struct symbol
*SysBase_sym
= NULL
;
421 for (i
=0; i
<numrel
; i
++, rel
++)
423 struct symbol
*sym
= &symtab
[ELF32_R_SYM(rel
->info
)];
424 ULONG
*p
= (ULONG
*)§ion
[rel
->offset
];
427 switch (sym
->shindex
)
431 D(bug("[ELF Loader] Undefined symbol '%s' while relocating the section '%s'\n",
432 (STRPTR
)sh
[shsymtab
->link
].addr
+ sym
->name
,
433 (STRPTR
)sh
[eh
->shstrndx
].addr
+ toreloc
->name
));
434 SetIoErr(ERROR_BAD_HUNK
);
438 D(bug("[ELF Loader] COMMON symbol '%s' while relocating the section '%s'\n",
439 (STRPTR
)sh
[shsymtab
->link
].addr
+ sym
->name
,
440 (STRPTR
)sh
[eh
->shstrndx
].addr
+ toreloc
->name
));
441 SetIoErr(ERROR_BAD_HUNK
);
446 if (SysBase_sym
== NULL
)
448 if (strncmp((STRPTR
)sh
[shsymtab
->link
].addr
+ sym
->name
, "SysBase", 8) == 0)
457 if (SysBase_sym
== sym
)
459 SysBase_yes
: s
= (ULONG
)&SysBase
;
462 SysBase_no
: s
= sym
->value
;
466 s
= (ULONG
)sh
[sym
->shindex
].addr
+ sym
->value
;
469 switch (ELF32_R_TYPE(rel
->info
))
471 #if defined(__i386__)
473 case R_386_32
: /* 32bit absolute */
477 case R_386_PC32
: /* 32bit PC relative */
484 #elif defined(__x86_64__)
485 /* These weren't tested */
486 case R_X86_64_64
: /* 64bit direct/absolute */
487 *p
= s
+ rel
->addend
;
490 case R_X86_64_PC32
: /* PC relative 32 bit signed */
491 *p
= s
+ rel
->addend
- (ULONG
)p
;
494 case R_X86_64_NONE
: /* No reloc */
497 #elif defined(__mc68000__)
500 *p
= s
+ rel
->addend
;
504 *p
= s
+ rel
->addend
- (ULONG
)p
;
510 #elif defined(__ppc__) || defined(__powerpc__)
513 *p
= s
+ rel
->addend
;
516 case R_PPC_ADDR16_LO
:
518 unsigned short *c
= (unsigned short *) p
;
519 *c
= (s
+ rel
->addend
) & 0xffff;
523 case R_PPC_ADDR16_HA
:
525 unsigned short *c
= (unsigned short *) p
;
526 ULONG temp
= s
+ rel
->addend
;
528 if ((temp
& 0x8000) != 0)
535 *p
|= (s
+ rel
->addend
- (ULONG
) p
) & 0x3fffffc;
539 *p
= s
+ rel
->addend
- (ULONG
) p
;
545 #elif defined(__arm__)
548 * This has not been tested. Taken from ARMELF.pdf
549 * from arm.com page 33ff.
552 *p
= s
+ rel
->addend
- (ULONG
)p
;
556 *p
= s
+ rel
->addend
;
563 # error Your architecture is not supported
567 D(bug("[ELF Loader] Unrecognized relocation type %d %d\n", i
, ELF32_R_TYPE(rel
->info
)));
568 SetIoErr(ERROR_BAD_HUNK
);
576 BPTR InternalLoadSeg_ELF
581 LONG
*stack __unused
,
582 struct DosLibrary
*DOSBase
588 BPTR
*next_hunk_ptr
= &hunks
;
590 BOOL exec_hunk_seen
= FALSE
;
592 /* Load Elf Header and Section Headers */
595 !read_block(file
, 0, &eh
, sizeof(eh
), funcarray
, DOSBase
) ||
596 !check_header(&eh
, DOSBase
) ||
597 !(sh
= load_block(file
, eh
.shoff
, eh
.shnum
* eh
.shentsize
, funcarray
, DOSBase
))
603 /* Iterate over the section headers in order to do some stuff... */
604 for (i
= 0; i
< eh
.shnum
; i
++)
607 Load the symbol and string table(s).
609 NOTICE: the ELF standard, at the moment (Nov 2002) explicitely states
610 that only one symbol table per file is allowed. However, it
611 also states that this may change in future... we already handle it.
613 if (sh
[i
].type
== SHT_SYMTAB
|| sh
[i
].type
== SHT_STRTAB
)
615 sh
[i
].addr
= load_block(file
, sh
[i
].offset
, sh
[i
].size
, funcarray
, DOSBase
);
620 /* Load the section in memory if needed, and make an hunk out of it */
621 if (sh
[i
].flags
& SHF_ALLOC
)
625 /* Only allow alignment if this is an executable hunk
626 or if an executable hunk has been loaded already,
627 so to avoid the situation in which a data hunk has its
628 content displaced from the hunk's header in case it's the
629 first hunk (this happens with Keymaps, for instance). */
630 if (sh
[i
].flags
& SHF_EXECINSTR
)
631 exec_hunk_seen
= TRUE
;
633 if (!load_hunk(file
, &next_hunk_ptr
, &sh
[i
], funcarray
, exec_hunk_seen
, DOSBase
))
640 /* Relocate the sections */
641 for (i
= 0; i
< eh
.shnum
; i
++)
645 #if defined(__i386__)
647 sh
[i
].type
== SHT_REL
&&
649 #elif defined(__x86_64__)
651 sh
[i
].type
== SHT_RELA
&&
653 #elif defined(__mc68000__)
655 sh
[i
].type
== SHT_RELA
&&
657 #elif defined(__ppc__) || defined(__powerpc__)
659 sh
[i
].type
== SHT_RELA
&&
661 #elif defined(__arm__)
662 #warning Missing code for ARM
666 # error Your architecture is not supported
669 /* Does this relocation section refer to a hunk? If so, addr must be != 0 */
673 sh
[i
].addr
= load_block(file
, sh
[i
].offset
, sh
[i
].size
, funcarray
, DOSBase
);
674 if (!sh
[i
].addr
|| !relocate(&eh
, sh
, i
, DOSBase
))
677 MyFree(sh
[i
].addr
, sh
[i
].size
);
687 /* There were some errors, deallocate The hunks */
689 InternalUnLoadSeg(hunks
, (VOID_FUNC
)funcarray
[2]);
694 /* Clear the caches to let the CPU see the new data and instructions */
699 struct hunk
*hunk
= BPTR2HUNK(curr
);
701 CacheClearE(hunk
->data
, hunk
->size
, CACRF_ClearD
| CACRF_ClearI
);
707 /* deallocate the symbol tables */
708 for (i
= 0; i
< eh
.shnum
; i
++)
710 if (((sh
[i
].type
== SHT_SYMTAB
) || (sh
[i
].type
== SHT_STRTAB
)) && (sh
[i
].addr
!= NULL
))
711 MyFree(sh
[i
].addr
, sh
[i
].size
);
714 /* Free the section headers */
715 MyFree(sh
, eh
.shnum
* eh
.shentsize
);