2 Copyright © 1995-2010, 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 <aros/config.h>
15 #include <aros/kernel.h>
16 #include <exec/memory.h>
17 #include <proto/exec.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>
31 #include <aros/macros.h>
33 #include "elf_intern.h"
42 struct DosLibrary
*DOSBase
45 UBYTE
*buf
= (UBYTE
*)buffer
;
48 if (Seek(file
, offset
, OFFSET_BEGINNING
) < 0)
53 subsize
= MyRead(file
, buf
, size
);
58 SetIoErr(ERROR_BAD_HUNK
);
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
);
86 if (read_block(file
, offset
, block
, size
, funcarray
, DOSBase
))
92 SetIoErr(ERROR_NO_FREE_STORE
);
97 int load_first_header(BPTR file
, struct elfheader
*eh
, SIPTR
*funcarray
, ULONG
*shnum
, ULONG
*shstrndx
, struct DosLibrary
*DOSBase
)
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
)
116 if (eh
->shoff
== 0) {
117 SetIoErr(ERROR_NOT_EXECUTABLE
);
121 if (!read_block(file
, eh
->shoff
, &sh
, sizeof(sh
), funcarray
, DOSBase
))
124 /* wider section header count is in the size field */
128 /* wider string table index is in the link field */
129 if (eh
->shstrndx
== SHN_XINDEX
)
132 /* sanity, if they're still invalid then this isn't elf */
133 if (*shnum
== 0 || *shstrndx
== SHN_XINDEX
)
135 SetIoErr(ERROR_NOT_EXECUTABLE
);
143 void register_elf(BPTR file
, BPTR hunks
, struct elfheader
*eh
, struct sheader
*sh
, struct DosLibrary
*DOSBase
)
145 #ifdef KrnRegisterModule
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 */
158 /* Now, go back until either ":" or "/" is found */
159 while(nameptr
> buffer
&& nameptr
[-1] != ':' && nameptr
[-1] != '/')
162 KrnRegisterModule(nameptr
, sh
, &eh
);
163 //KrnRegisterModule(nameptr, hunks, DEBUG_ELF, &dbg);
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
))
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
);
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
);
206 BPTR
**next_hunk_ptr
,
210 struct DosLibrary
*DOSBase
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
);
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);
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. */
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
);
253 sh
->addr
= (char *)AROS_ROUNDUP2((IPTR
)hunk
->data
, sh
->addralign
);
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
);
273 SetIoErr(ERROR_NO_FREE_STORE
);
280 struct elfheader
*eh
,
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 */
300 ULONG numrel
= shrel
->size
/ shrel
->entsize
;
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
*)§ion
[rel
->offset
];
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
)
322 if (sym
->shindex
!= SHN_XINDEX
)
323 shindex
= sym
->shindex
;
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
);
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
));
340 D(bug("[ELF Loader] Undefined symbol '%s'\n",
341 (STRPTR
)sh
[SHINDEX(shsymtab
->link
)].addr
+ sym
->name
));
342 SetIoErr(ERROR_BAD_HUNK
);
346 D(bug("[ELF Loader] COMMON symbol '%s'\n",
347 (STRPTR
)sh
[SHINDEX(shsymtab
->link
)].addr
+ sym
->name
));
348 SetIoErr(ERROR_BAD_HUNK
);
353 if (SysBase_sym
== NULL
)
355 if (strncmp((STRPTR
)sh
[SHINDEX(shsymtab
->link
)].addr
+ sym
->name
, "SysBase", 8) == 0)
364 if (SysBase_sym
== sym
)
366 SysBase_yes
: s
= (IPTR
)&SysBase
;
369 SysBase_no
: s
= sym
->value
;
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 */
384 case R_386_PC32
: /* 32bit PC relative */
391 #elif defined(__x86_64__)
392 case R_X86_64_64
: /* 64bit direct/absolute */
393 *(UQUAD
*)p
= s
+ rel
->addend
;
396 case R_X86_64_PC32
: /* PC relative 32 bit signed */
397 *(ULONG
*)p
= s
+ rel
->addend
- (IPTR
) p
;
401 *(ULONG
*)p
= (UQUAD
)s
+ (UQUAD
)rel
->addend
;
405 *(LONG
*)p
= (QUAD
)s
+ (QUAD
)rel
->addend
;
408 case R_X86_64_NONE
: /* No reloc */
411 #elif defined(__mc68000__)
414 *p
= s
+ rel
->addend
;
418 *p
= s
+ rel
->addend
- (ULONG
)p
;
424 #elif defined(__ppc__) || defined(__powerpc__)
427 *p
= s
+ rel
->addend
;
430 case R_PPC_ADDR16_LO
:
432 unsigned short *c
= (unsigned short *) p
;
433 *c
= (s
+ rel
->addend
) & 0xffff;
437 case R_PPC_ADDR16_HA
:
439 unsigned short *c
= (unsigned short *) p
;
440 ULONG temp
= s
+ rel
->addend
;
442 if ((temp
& 0x8000) != 0)
449 unsigned short *c
= (unsigned short *) p
;
450 *c
= (s
+ rel
->addend
- (ULONG
) p
) & 0xffff;
456 unsigned short *c
= (unsigned short *) p
;
457 ULONG temp
= s
+ rel
->addend
- (ULONG
) p
;
459 if ((temp
& 0x8000) != 0)
466 *p
|= (s
+ rel
->addend
- (ULONG
) p
) & 0x3fffffc;
470 *p
= s
+ rel
->addend
- (ULONG
) p
;
476 #elif defined(__arm__)
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
;
491 *p
|= offset
& 0x00ffffff;
495 case R_ARM_MOVW_ABS_NC
:
498 signed long offset
= *p
;
499 offset
= ((offset
& 0xf0000) >> 4) | (offset
& 0xfff);
500 offset
= (offset
^ 0x8000) - 0x8000;
504 if (ELF_R_TYPE(rel
->info
) == R_ARM_MOVT_ABS
)
508 *p
|= ((offset
& 0xf000) << 4) | (offset
& 0x0fff);
520 # error Your architecture is not supported
524 D(bug("[ELF Loader] Unrecognized relocation type %d %d\n", i
, ELF_R_TYPE(rel
->info
)));
525 SetIoErr(ERROR_BAD_HUNK
);
533 BPTR InternalLoadSeg_ELF
538 SIPTR
*stack __unused
,
539 struct DosLibrary
*DOSBase
544 struct sheader
*symtab_shndx
= NULL
;
546 BPTR
*next_hunk_ptr
= &hunks
;
548 BOOL exec_hunk_seen
= FALSE
;
552 /* load and validate ELF header */
553 if (!load_header(file
, &eh
, funcarray
, DOSBase
))
556 if (!load_first_header(file
, &eh
, funcarray
, &int_shnum
, &int_shstrndx
, DOSBase
))
559 /* load section headers */
560 if (!(sh
= load_block(file
, eh
.shoff
, int_shnum
* eh
.shentsize
, funcarray
, DOSBase
)))
563 /* load the string table */
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
);
589 if (sh
[i
].type
== SHT_SYMTAB_SHNDX
) {
590 if (symtab_shndx
== NULL
)
591 symtab_shndx
= &sh
[i
];
593 D(bug("[ELF Loader] file contains multiple symtab shndx tables. only using the first one\n"));
597 /* Load the section in memory if needed, and make an hunk out of it */
598 if (sh
[i
].flags
& SHF_ALLOC
)
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
))
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
))
627 MyFree(sh
[i
].addr
, sh
[i
].size
);
632 /* Everything is loaded now. Register the module at kernel.resource */
633 register_elf(file
, hunks
, &eh
, sh
, DOSBase
);
638 /* There were some errors, deallocate The hunks */
640 InternalUnLoadSeg(hunks
, (VOID_FUNC
)funcarray
[2]);
645 /* Clear the caches to let the CPU see the new data and instructions */
650 struct hunk
*hunk
= BPTR2HUNK(BADDR(curr
));
652 CacheClearE(hunk
->data
, hunk
->size
, CACRF_ClearD
| CACRF_ClearI
);
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
);