2 Copyright © 1995-2011, 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.
12 #include <aros/asmcall.h>
13 #include <aros/config.h>
14 #include <aros/debug.h>
15 #include <aros/macros.h>
16 #include <exec/memory.h>
18 #include <dos/dosasl.h>
19 #include <libraries/debug.h>
20 #include <proto/dos.h>
21 #include <proto/arossupport.h>
22 #include <proto/debug.h>
23 #include <proto/exec.h>
28 #include "internalloadseg.h"
29 #include "dos_intern.h"
36 } __attribute__((packed
));
38 #define BPTR2HUNK(bptr) ((struct hunk *)((void *)bptr - offsetof(struct hunk, next)))
39 #define HUNK2BPTR(hunk) MKBADDR(&hunk->next)
48 struct DosLibrary
*DOSBase
51 UBYTE
*buf
= (UBYTE
*)buffer
;
54 if (ilsSeek(file
, offset
, OFFSET_BEGINNING
) < 0)
59 subsize
= ilsRead(file
, buf
, size
);
64 SetIoErr(ERROR_BAD_HUNK
);
76 static void *load_block
82 struct DosLibrary
*DOSBase
85 D(bug("[ELF Loader] Load Block\n"));
86 D(bug("[ELF Loader] (size=%d)\n",size
));
87 D(bug("[ELF Loader] (funcarray=0x%x)\n",funcarray
));
88 D(bug("[ELF Loader] (funcarray[1]=0x%x)\n",funcarray
[1]));
89 void *block
= ilsAllocMem(size
, MEMF_ANY
);
92 if (read_block(file
, offset
, block
, size
, funcarray
, DOSBase
))
95 ilsFreeMem(block
, size
);
98 SetIoErr(ERROR_NO_FREE_STORE
);
103 static ULONG
read_shnum(BPTR file
, struct elfheader
*eh
, SIPTR
*funcarray
, struct DosLibrary
*DOSBase
)
105 ULONG shnum
= eh
->shnum
;
107 /* the ELF header only uses 16 bits to store the count of section headers,
108 * so it can't handle more than 65535 headers. if the count is 0, and an
109 * offset is defined, then the real count can be found in the first
110 * section header (which always exists).
112 * similarly, if the string table index is SHN_XINDEX, then the actual
113 * index is found in the first section header also.
115 * see the System V ABI 2001-04-24 draft for more details.
121 if (eh
->shoff
== 0) {
122 SetIoErr(ERROR_NOT_EXECUTABLE
);
126 if (!read_block(file
, eh
->shoff
, &sh
, sizeof(sh
), funcarray
, DOSBase
))
129 /* wider section header count is in the size field */
132 /* sanity, if they're still invalid then this isn't elf */
134 SetIoErr(ERROR_NOT_EXECUTABLE
);
140 static void register_elf(BPTR file
, BPTR hunks
, struct elfheader
*eh
, struct sheader
*sh
, struct DosLibrary
*DOSBase
)
146 if (NameFromFH(file
, buffer
, sizeof(buffer
)))
148 char *nameptr
= buffer
;
149 struct ELF_DebugInfo dbg
= {eh
, sh
};
151 /* gdb support needs full paths */
152 #if !AROS_MODULES_DEBUG
153 /* First, go through the name, till end of the string */
155 /* Now, go back until either ":" or "/" is found */
156 while(nameptr
> buffer
&& nameptr
[-1] != ':' && nameptr
[-1] != '/')
159 RegisterModule(nameptr
, hunks
, DEBUG_ELF
, &dbg
);
164 static int load_header(BPTR file
, struct elfheader
*eh
, SIPTR
*funcarray
, struct DosLibrary
*DOSBase
) {
165 ilsSeek(file
, OFFSET_BEGINNING
, 0);
166 if (!read_block(file
, 0, eh
, sizeof(struct elfheader
), funcarray
, DOSBase
))
169 if (eh
->ident
[0] != 0x7f || eh
->ident
[1] != 'E' ||
170 eh
->ident
[2] != 'L' || eh
->ident
[3] != 'F') {
171 D(bug("[ELF Loader] Not an ELF object\n"));
172 SetIoErr(ERROR_NOT_EXECUTABLE
);
175 D(bug("[ELF Loader] ELF object\n"));
177 /* WANT_CLASS should be defined for your target */
178 if (eh
->ident
[EI_CLASS
] != AROS_ELF_CLASS
||
179 eh
->ident
[EI_VERSION
] != EV_CURRENT
||
180 eh
->type
!= ET_REL
||
181 eh
->ident
[EI_DATA
] != AROS_ELF_DATA
||
182 eh
->machine
!= AROS_ELF_MACHINE
)
184 D(bug("[ELF Loader] Object is of wrong type\n"));
185 D(bug("[ELF Loader] EI_CLASS is %d - should be %d\n", eh
->ident
[EI_CLASS
] , AROS_ELF_CLASS
));
186 D(bug("[ELF Loader] EI_VERSION is %d - should be %d\n", eh
->ident
[EI_VERSION
], EV_CURRENT
));
187 D(bug("[ELF Loader] type is %d - should be %d\n", eh
->type
, ET_REL
));
188 D(bug("[ELF Loader] EI_DATA is %d - should be %d\n", eh
->ident
[EI_DATA
] , AROS_ELF_DATA
));
189 D(bug("[ELF Loader] machine is %d - should be %d\n", eh
->machine
, AROS_ELF_MACHINE
));
191 SetIoErr(ERROR_NOT_EXECUTABLE
);
201 BPTR
**next_hunk_ptr
,
205 struct DosLibrary
*DOSBase
214 /* The size of the hunk is the size of the section, plus
215 the size of the hunk structure, plus the size of the alignment (if necessary)*/
216 hunk_size
= sh
->size
+ sizeof(struct hunk
);
220 hunk_size
+= sh
->addralign
;
222 /* Also create space for a trampoline, if necessary */
223 if (sh
->flags
& SHF_EXECINSTR
)
224 hunk_size
+= sizeof(struct FullJumpVec
);
227 hunk
= ilsAllocMem(hunk_size
, MEMF_ANY
| (sh
->type
== SHT_NOBITS
) ? MEMF_CLEAR
: 0);
231 hunk
->size
= hunk_size
;
233 /* In case we are required to honour alignment, and If this section contains
234 executable code, create a trampoline to its beginning, so that even if the
235 alignment requirements make the actual code go much after the end of the
236 hunk structure, the code can still be reached in the usual way. */
239 if (sh
->flags
& SHF_EXECINSTR
)
241 sh
->addr
= (char *)AROS_ROUNDUP2
243 (IPTR
)hunk
->data
+ sizeof(struct FullJumpVec
), sh
->addralign
245 __AROS_SET_FULLJMP((struct FullJumpVec
*)hunk
->data
, sh
->addr
);
248 sh
->addr
= (char *)AROS_ROUNDUP2((IPTR
)hunk
->data
, sh
->addralign
);
251 sh
->addr
= hunk
->data
;
253 /* Link the previous one with the new one */
254 BPTR2HUNK(*next_hunk_ptr
)->next
= HUNK2BPTR(hunk
);
256 D(bug("[dos] hunk @ %p, size=%08x, addr @ %p\n", hunk
, hunk
->size
, sh
->addr
));
258 /* Update the pointer to the previous one, which is now the current one */
259 *next_hunk_ptr
= &hunk
->next
;
261 if (sh
->type
!= SHT_NOBITS
)
262 return read_block(file
, sh
->offset
, sh
->addr
, sh
->size
, funcarray
, DOSBase
);
268 SetIoErr(ERROR_NO_FREE_STORE
);
275 struct elfheader
*eh
,
278 struct sheader
*symtab_shndx
,
279 struct DosLibrary
*DOSBase
282 struct sheader
*shrel
= &sh
[shrel_idx
];
283 struct sheader
*shsymtab
= &sh
[SHINDEX(shrel
->link
)];
284 struct sheader
*toreloc
= &sh
[SHINDEX(shrel
->info
)];
286 struct symbol
*symtab
= (struct symbol
*)shsymtab
->addr
;
287 struct relo
*rel
= (struct relo
*)shrel
->addr
;
290 * Ignore relocs if the target section has no allocation. that can happen
291 * eg. with a .debug PROGBITS and a .rel.debug section
293 if (!(toreloc
->flags
& SHF_ALLOC
))
296 ULONG numrel
= shrel
->size
/ shrel
->entsize
;
299 #ifndef NO_SYSBASE_REMAP
300 struct symbol
*SysBase_sym
= NULL
;
303 for (i
=0; i
<numrel
; i
++, rel
++)
312 * R_ARM_V4BX are actually special marks for the linker.
313 * They even never have a target (shindex == SHN_UNDEF),
314 * so we simply ignore them before doing any checks.
316 if (ELF_R_TYPE(rel
->info
) == R_ARM_V4BX
)
320 sym
= &symtab
[ELF_R_SYM(rel
->info
)];
321 p
= toreloc
->addr
+ rel
->offset
;
323 if (sym
->shindex
!= SHN_XINDEX
)
324 shindex
= sym
->shindex
;
327 if (symtab_shndx
== NULL
) {
328 D(bug("[ELF Loader] got symbol with shndx 0xfff, but there's no symtab shndx table\n"));
329 SetIoErr(ERROR_BAD_HUNK
);
332 shindex
= ((ULONG
*)symtab_shndx
->addr
)[ELF_R_SYM(rel
->info
)];
335 DB2(bug("[ELF Loader] Processing symbol %s\n", sh
[SHINDEX(shsymtab
->link
)].addr
+ sym
->name
));
341 D(bug("[ELF Loader] Undefined symbol '%s'\n",
342 (STRPTR
)sh
[SHINDEX(shsymtab
->link
)].addr
+ sym
->name
));
343 SetIoErr(ERROR_BAD_HUNK
);
347 D(bug("[ELF Loader] COMMON symbol '%s'\n",
348 (STRPTR
)sh
[SHINDEX(shsymtab
->link
)].addr
+ sym
->name
));
349 SetIoErr(ERROR_BAD_HUNK
);
354 #ifdef NO_SYSBASE_REMAP
357 if (SysBase_sym
== NULL
)
359 if (strncmp((STRPTR
)sh
[SHINDEX(shsymtab
->link
)].addr
+ sym
->name
, "SysBase", 8) == 0)
368 if (SysBase_sym
== sym
)
370 SysBase_yes
: s
= (IPTR
)&SysBase
;
373 SysBase_no
: s
= sym
->value
;
378 s
= (IPTR
)sh
[SHINDEX(shindex
)].addr
+ sym
->value
;
381 switch (ELF_R_TYPE(rel
->info
))
383 #if defined(__i386__)
385 case R_386_32
: /* 32bit absolute */
389 case R_386_PC32
: /* 32bit PC relative */
396 #elif defined(__x86_64__)
397 case R_X86_64_64
: /* 64bit direct/absolute */
398 *(UQUAD
*)p
= s
+ rel
->addend
;
401 case R_X86_64_PC32
: /* PC relative 32 bit signed */
402 *(ULONG
*)p
= s
+ rel
->addend
- (IPTR
) p
;
406 *(ULONG
*)p
= (UQUAD
)s
+ (UQUAD
)rel
->addend
;
410 *(LONG
*)p
= (QUAD
)s
+ (QUAD
)rel
->addend
;
413 case R_X86_64_NONE
: /* No reloc */
416 #elif defined(__mc68000__)
419 *p
= s
+ rel
->addend
;
423 *(UWORD
*)p
= s
+ rel
->addend
;
427 *(UBYTE
*)p
= s
+ rel
->addend
;
431 *p
= s
+ rel
->addend
- (ULONG
)p
;
435 *(UWORD
*)p
= s
+ rel
->addend
- (ULONG
)p
;
439 *(UBYTE
*)p
= s
+ rel
->addend
- (ULONG
)p
;
445 #elif defined(__ppc__) || defined(__powerpc__)
448 *p
= s
+ rel
->addend
;
451 case R_PPC_ADDR16_LO
:
453 unsigned short *c
= (unsigned short *) p
;
454 *c
= (s
+ rel
->addend
) & 0xffff;
458 case R_PPC_ADDR16_HA
:
460 unsigned short *c
= (unsigned short *) p
;
461 ULONG temp
= s
+ rel
->addend
;
463 if ((temp
& 0x8000) != 0)
470 unsigned short *c
= (unsigned short *) p
;
471 *c
= (s
+ rel
->addend
- (ULONG
) p
) & 0xffff;
477 unsigned short *c
= (unsigned short *) p
;
478 ULONG temp
= s
+ rel
->addend
- (ULONG
) p
;
480 if ((temp
& 0x8000) != 0)
487 *p
|= (s
+ rel
->addend
- (ULONG
) p
) & 0x3fffffc;
491 *p
= s
+ rel
->addend
- (ULONG
) p
;
497 #elif defined(__arm__)
502 /* On ARM the 24 bit offset is shifted by 2 to the right */
503 signed long offset
= (*p
& 0x00ffffff) << 2;
504 /* If highest bit set, make offset negative */
505 if (offset
& 0x02000000)
506 offset
-= 0x04000000;
508 if (offset
>= 0x02000000 ||
509 offset
<= -0x02000000)
511 bug("[ELF Loader] Relocation type %d %d out of range!\n", i
, ELF_R_TYPE(rel
->info
));
512 SetIoErr(ERROR_BAD_HUNK
);
515 offset
+= s
- (ULONG
)p
;
519 *p
|= offset
& 0x00ffffff;
524 case R_ARM_THM_JUMP24
:
526 ULONG upper
,lower
,sign
,j1
,j2
;
529 upper
= *((UWORD
*)p
);
530 lower
= *((UWORD
*)p
+1);
532 sign
= (upper
>> 10) & 1;
533 j1
= (lower
>> 13) & 1;
534 j2
= (lower
>> 11) & 1;
536 offset
= (sign
<< 24) | ((~(j1
^ sign
) & 1) << 23) |
537 ((~(j2
^ sign
) & 1) << 22) |
538 ((upper
& 0x03ff) << 12) |
539 ((lower
& 0x07ff) << 1);
541 if (offset
& 0x01000000)
542 offset
-= 0x02000000;
544 if (offset
>= 0x01000000 ||
545 offset
<= -0x01000000)
547 bug("[ELF Loader] Relocation type %d %d out of range!\n", i
, ELF_R_TYPE(rel
->info
));
548 SetIoErr(ERROR_BAD_HUNK
);
551 offset
+= s
- (ULONG
)p
;
553 sign
= (offset
>> 24) & 1;
554 j1
= sign
^ (~(offset
>> 23) & 1);
555 j2
= sign
^ (~(offset
>> 22) & 1);
557 *(UWORD
*)p
= (UWORD
)((upper
& 0xf800) | (sign
<< 10) |
558 ((offset
>> 12) & 0x03ff));
559 *((UWORD
*)p
+ 1) = (UWORD
)((lower
& 0xd000) |
560 (j1
<< 13) | (j2
<< 11) | ((offset
>> 1) & 0x07ff));
565 case R_ARM_THM_MOVW_ABS_NC
:
566 case R_ARM_THM_MOVT_ABS
:
571 upper
= *((UWORD
*)p
);
572 lower
= *((UWORD
*)p
+1);
574 offset
= ((upper
& 0x000f) << 12) |
575 ((upper
& 0x0400) << 1) |
576 ((lower
& 0x7000) >> 4) |
579 offset
= (offset
^ 0x8000) - 0x8000;
583 if (ELF_R_TYPE(rel
->info
) == R_ARM_THM_MOVT_ABS
)
586 *(UWORD
*)p
= (UWORD
)((upper
& 0xfbf0) |
587 ((offset
& 0xf000) >> 12) |
588 ((offset
& 0x0800) >> 1));
589 *((UWORD
*)p
+ 1) = (UWORD
)((lower
& 0x8f00) |
590 ((offset
& 0x0700)<< 4) |
595 case R_ARM_MOVW_ABS_NC
:
598 signed long offset
= *p
;
599 offset
= ((offset
& 0xf0000) >> 4) | (offset
& 0xfff);
600 offset
= (offset
^ 0x8000) - 0x8000;
604 if (ELF_R_TYPE(rel
->info
) == R_ARM_MOVT_ABS
)
608 *p
|= ((offset
& 0xf000) << 4) | (offset
& 0x0fff);
620 # error Your architecture is not supported
624 D(bug("[ELF Loader] Unrecognized relocation type %d %d\n", i
, ELF_R_TYPE(rel
->info
)));
625 SetIoErr(ERROR_BAD_HUNK
);
633 BPTR InternalLoadSeg_ELF
638 LONG
*stack __unused
,
639 struct DosLibrary
*DOSBase
644 struct sheader
*symtab_shndx
= NULL
;
646 BPTR
*next_hunk_ptr
= &hunks
;
648 BOOL exec_hunk_seen
= FALSE
;
651 /* load and validate ELF header */
652 if (!load_header(file
, &eh
, funcarray
, DOSBase
))
655 int_shnum
= read_shnum(file
, &eh
, funcarray
, DOSBase
);
659 /* load section headers */
660 if (!(sh
= load_block(file
, eh
.shoff
, int_shnum
* eh
.shentsize
, funcarray
, DOSBase
)))
663 /* Iterate over the section headers in order to do some stuff... */
664 for (i
= 0; i
< int_shnum
; i
++)
667 Load the symbol and string table(s).
669 NOTICE: the ELF standard, at the moment (Nov 2002) explicitely states
670 that only one symbol table per file is allowed. However, it
671 also states that this may change in future... we already handle it.
673 if (sh
[i
].type
== SHT_SYMTAB
|| sh
[i
].type
== SHT_STRTAB
|| sh
[i
].type
== SHT_SYMTAB_SHNDX
)
675 sh
[i
].addr
= load_block(file
, sh
[i
].offset
, sh
[i
].size
, funcarray
, DOSBase
);
679 if (sh
[i
].type
== SHT_SYMTAB_SHNDX
) {
680 if (symtab_shndx
== NULL
)
681 symtab_shndx
= &sh
[i
];
683 D(bug("[ELF Loader] file contains multiple symtab shndx tables. only using the first one\n"));
687 /* Load the section in memory if needed, and make a hunk out of it */
688 if (sh
[i
].flags
& SHF_ALLOC
)
692 /* Only allow alignment if this is an executable hunk
693 or if an executable hunk has been loaded already,
694 so to avoid the situation in which a data hunk has its
695 content displaced from the hunk's header in case it's the
696 first hunk (this happens with Keymaps, for instance). */
697 if (sh
[i
].flags
& SHF_EXECINSTR
)
698 exec_hunk_seen
= TRUE
;
700 if (!load_hunk(file
, &next_hunk_ptr
, &sh
[i
], funcarray
, exec_hunk_seen
, DOSBase
))
707 /* Relocate the sections */
708 for (i
= 0; i
< int_shnum
; i
++)
710 /* Does this relocation section refer to a hunk? If so, addr must be != 0 */
711 if ((sh
[i
].type
== AROS_ELF_REL
) && sh
[SHINDEX(sh
[i
].info
)].addr
)
713 sh
[i
].addr
= load_block(file
, sh
[i
].offset
, sh
[i
].size
, funcarray
, DOSBase
);
714 if (!sh
[i
].addr
|| !relocate(&eh
, sh
, i
, symtab_shndx
, DOSBase
))
717 ilsFreeMem(sh
[i
].addr
, sh
[i
].size
);
722 /* Everything is loaded now. Register the module at kernel.resource */
723 register_elf(file
, hunks
, &eh
, sh
, DOSBase
);
728 /* There were some errors, deallocate The hunks */
730 InternalUnLoadSeg(hunks
, (VOID_FUNC
)funcarray
[2]);
735 /* Clear the caches to let the CPU see the new data and instructions */
740 struct hunk
*hunk
= BPTR2HUNK(BADDR(curr
));
742 CacheClearE(hunk
->data
, hunk
->size
, CACRF_ClearD
| CACRF_ClearI
);
748 /* deallocate the symbol tables */
749 for (i
= 0; i
< int_shnum
; i
++)
751 if (((sh
[i
].type
== SHT_SYMTAB
) || (sh
[i
].type
== SHT_STRTAB
)) && (sh
[i
].addr
!= NULL
))
752 ilsFreeMem(sh
[i
].addr
, sh
[i
].size
);
755 /* Free the section headers */
756 ilsFreeMem(sh
, int_shnum
* eh
.shentsize
);