2 Copyright (C) 2006-2011 The AROS Development Team. All rights reserved.
5 Desc: ELF loader extracted from our internal_load_seg_elf in dos.library.
14 /* Define this wrapper here, before loading AROS headers,
15 * so that the defines in <aros/system.h> do not
16 * confuse GCC's built-in substitutions for strcmp().
18 static inline int Strcmp(const char *a
, const char *b
) { return strcmp(a
, b
); }
21 #include <libraries/debug.h>
23 #include <elfloader.h>
30 /* Use own definitions because we may be compiled as 32-bit code but build structures for 64-bit code */
31 struct ELF_ModuleInfo_t
36 unsigned short Pad0
; /* On i386 we have different alignment, so do explicit padding */
44 /* Our own definition of struct KernelBSS, to avoid excessive castings */
51 static elf_uintptr_t SysBase_ptr
= 0;
54 * Test for correct ELF header here
56 static char *check_header(struct elfheader
*eh
)
58 if (eh
->ident
[0] != 0x7f || eh
->ident
[1] != 'E' ||
59 eh
->ident
[2] != 'L' || eh
->ident
[3] != 'F')
60 return "Not a ELF file";
62 if (eh
->type
!= ET_REL
|| eh
->machine
!= AROS_ELF_MACHINE
)
63 return "Wrong object type or wrong architecture";
70 * Get the memory for chunk and load it
72 static void *load_hunk(void *file
, struct sheader
*sh
, void *addr
, struct KernelBSS_t
**bss_tracker
)
76 /* empty chunk? Who cares :) */
80 D(kprintf("[ELF Loader] Chunk (%ld bytes, align=%ld (%p) @ ", sh
->size
, sh
->addralign
, (void *)sh
->addralign
));
81 align
= sh
->addralign
- 1;
82 addr
= (char *)(((uintptr_t)addr
+ align
) & ~align
);
84 D(kprintf("%p\n", addr
));
85 sh
->addr
= (elf_ptr_t
)(uintptr_t)addr
;
87 /* copy block of memory from ELF file if it exists */
88 if (sh
->type
!= SHT_NOBITS
)
90 if (read_block(file
, sh
->offset
, (void *)(uintptr_t)sh
->addr
, sh
->size
))
95 memset(addr
, 0, sh
->size
);
97 (*bss_tracker
)->addr
= (uintptr_t)addr
;
98 (*bss_tracker
)->len
= sh
->size
;
102 return addr
+ sh
->size
;
105 static void *copy_data(void *src
, void *addr
, uintptr_t len
)
107 memcpy(addr
, src
, len
);
111 /* Perform relocations of given section */
112 static int relocate(struct elfheader
*eh
, struct sheader
*sh
, long shrel_idx
, elf_uintptr_t DefSysBase
)
114 struct sheader
*shrel
= &sh
[shrel_idx
];
115 struct sheader
*shsymtab
= &sh
[shrel
->link
];
116 struct sheader
*toreloc
= &sh
[shrel
->info
];
118 struct symbol
*symtab
= (struct symbol
*)(uintptr_t)shsymtab
->addr
;
119 struct relo
*rel
= (struct relo
*)(uintptr_t)shrel
->addr
;
120 /* Early cast to uintptr_t omits __udivdi3 call in x86-64 native bootstrap */
121 unsigned int numrel
= (uintptr_t)shrel
->size
/ (uintptr_t)shrel
->entsize
;
124 struct symbol
*SysBase_sym
= NULL
;
127 * Ignore relocs if the target section has no allocation. that can happen
128 * eg. with a .debug PROGBITS and a .rel.debug section
130 if (!(toreloc
->flags
& SHF_ALLOC
))
133 DREL(kprintf("[ELF Loader] performing %d relocations\n", numrel
));
135 for (i
=0; i
<numrel
; i
++, rel
++)
137 struct symbol
*sym
= &symtab
[ELF_R_SYM(rel
->info
)];
138 uintptr_t *p
= (void *)(uintptr_t)toreloc
->addr
+ rel
->offset
;
139 const char *name
= (const char *)(uintptr_t)sh
[shsymtab
->link
].addr
+ sym
->name
;
144 * R_ARM_V4BX are actually special marks for the linker.
145 * They even never have a target (shindex == SHN_UNDEF),
146 * so we simply ignore them before doing any checks.
148 if (ELF_R_TYPE(rel
->info
) == R_ARM_V4BX
)
152 switch (sym
->shindex
)
155 if (Strcmp(name
, "SysBase") == 0) {
158 SysBase_ptr
= DefSysBase
;
159 D(kprintf("[ELF Loader] SysBase pointer set to default %p\n", (void *)SysBase_ptr
));
164 kprintf("[ELF Loader] Undefined symbol '%s'\n", name
);
170 kprintf("[ELF Loader] COMMON symbol '%s'\n", name
);
174 if (SysBase_sym
== NULL
)
176 if (Strcmp(name
, "SysBase") == 0)
178 DREL(kprintf("[ELF Loader] got SysBase\n"));
183 if (SysBase_sym
== sym
)
187 SysBase_ptr
= DefSysBase
;
188 D(kprintf("[ELF Loader] SysBase pointer set to default %p\n", (void *)SysBase_ptr
));
198 s
= (uintptr_t)sh
[sym
->shindex
].addr
+ sym
->value
;
203 * The first global data symbol named SysBase becomes global SysBase.
204 * The idea behind: the first module (kernel.resource) contains global
205 * SysBase variable and all other modules are linked to it.
207 if (sym
->info
== ELF_S_INFO(STB_GLOBAL
, STT_OBJECT
))
209 if (Strcmp(name
, "SysBase") == 0)
212 D(kprintf("[ELF Loader] SysBase pointer set to %p\n", (void *)SysBase_ptr
));
218 DREL(kprintf("[ELF Loader] Relocating symbol %s type ", sym
->name
? name
: "<unknown>"));
219 switch (ELF_R_TYPE(rel
->info
))
222 case R_X86_64_64
: /* 64bit direct/absolute */
223 *(uint64_t *)p
= s
+ rel
->addend
;
226 case R_X86_64_PC32
: /* PC relative 32 bit signed */
227 *(uint32_t *)p
= s
+ rel
->addend
- (uintptr_t) p
;
231 *(uint32_t *)p
= (uint64_t)s
+ (uint64_t)rel
->addend
;
235 *(int32_t *)p
= (int64_t)s
+ (int64_t)rel
->addend
;
238 case R_X86_64_NONE
: /* No reloc */
242 case R_386_32
: /* 32bit absolute */
243 DREL(kprintf("R_386_32"));
247 case R_386_PC32
: /* 32bit PC relative */
248 DREL(kprintf("R_386_PC32"));
249 *p
+= (s
- (uintptr_t)p
);
253 DREL(kprintf("R_386_NONE"));
259 *p
= s
+ rel
->addend
;
263 *p
= s
+ rel
->addend
- (uint32_t)p
;
269 #if defined(__ppc__) || defined(__powerpc__)
271 *p
= s
+ rel
->addend
;
274 case R_PPC_ADDR16_LO
:
276 unsigned short *c
= (unsigned short *) p
;
277 *c
= (s
+ rel
->addend
) & 0xffff;
281 case R_PPC_ADDR16_HA
:
283 unsigned short *c
= (unsigned short *) p
;
284 uint32_t temp
= s
+ rel
->addend
;
286 if ((temp
& 0x8000) != 0)
293 unsigned short *c
= (unsigned short *) p
;
294 *c
= (s
+ rel
->addend
- (uint32_t)p
) & 0xffff;
300 unsigned short *c
= (unsigned short *) p
;
301 uint32_t temp
= s
+ rel
->addend
- (uint32_t)p
;
303 if ((temp
& 0x8000) != 0)
310 *p
|= (s
+ rel
->addend
- (uint32_t)p
) & 0x3fffffc;
314 *p
= s
+ rel
->addend
- (uint32_t)p
;
326 /* On ARM the 24 bit offset is shifted by 2 to the right */
327 signed long offset
= (*p
& 0x00ffffff) << 2;
328 /* If highest bit set, make offset negative */
329 if (offset
& 0x02000000)
330 offset
-= 0x04000000;
332 offset
+= s
- (uint32_t)p
;
336 *p
|= offset
& 0x00ffffff;
340 case R_ARM_MOVW_ABS_NC
:
343 signed long offset
= *p
;
344 offset
= ((offset
& 0xf0000) >> 4) | (offset
& 0xfff);
345 offset
= (offset
^ 0x8000) - 0x8000;
349 if (ELF_R_TYPE(rel
->info
) == R_ARM_MOVT_ABS
)
353 *p
|= ((offset
& 0xf000) << 4) | (offset
& 0x0fff);
365 kprintf("[ELF Loader] Unrecognized relocation type %d %ld\n", i
, (long)ELF_R_TYPE(rel
->info
));
368 DREL(kprintf(" -> %p\n", *p
));
373 int GetKernelSize(struct ELFNode
*FirstELF
, unsigned long *ro_size
, unsigned long *rw_size
, unsigned long *bss_size
)
376 unsigned long ksize
= 0;
377 unsigned long rwsize
= 0;
378 unsigned long bsize
= sizeof(struct KernelBSS_t
);
381 kprintf("[ELF Loader] Calculating kickstart size...\n");
383 for (n
= FirstELF
; n
; n
= n
->Next
)
389 D(kprintf("[ELF Loader] Checking file %s\n", n
->Name
));
391 file
= open_file(n
, &err
);
394 DisplayError("Failed to open file %s!\n", n
->Name
);
398 /* Check the header of ELF file */
399 n
->eh
= load_block(file
, 0, sizeof(struct elfheader
), &err
);
402 errstr
= "Failed to read file header";
406 errstr
= check_header(n
->eh
);
409 n
->sh
= load_block(file
, n
->eh
->shoff
, n
->eh
->shnum
* n
->eh
->shentsize
, &err
);
412 errstr
= "Failed to read section headers";
420 DisplayError("%s: %s\n", n
->Name
, errstr
);
425 * Debug data for the module includes:
426 * - Module descriptor (struct ELF_ModuleInfo_t)
428 * - ELF section header
430 * - One empty pointer for alignment
432 ksize
+= (sizeof(struct ELF_ModuleInfo_t
) + sizeof(struct elfheader
) + n
->eh
->shnum
* n
->eh
->shentsize
+
433 strlen(n
->Name
) + sizeof(void *));
435 /* Go through all sections and calculate kernel size */
436 for(i
= 0; i
< n
->eh
->shnum
; i
++)
438 /* Ignore sections with zero lengths */
444 * - Actual code and data (allocated sections)
445 * - String tables (for debug data)
446 * - Symbol tables (for debug data)
448 if ((n
->sh
[i
].flags
& SHF_ALLOC
) || (n
->sh
[i
].type
== SHT_STRTAB
) || (n
->sh
[i
].type
== SHT_SYMTAB
))
450 /* Add maximum space for alignment */
451 unsigned long s
= n
->sh
[i
].size
+ n
->sh
[i
].addralign
- 1;
453 if (n
->sh
[i
].flags
& SHF_WRITE
)
458 if (n
->sh
[i
].type
== SHT_NOBITS
)
459 bsize
+= sizeof(struct KernelBSS_t
);
470 kprintf("[ELF Loader] Code %lu bytes, data %lu bytes, BSS array %lu bytes\n", ksize
, rwsize
, bsize
);
476 * This function loads the listed modules.
477 * It expects that ELF and section header pointers in the list are already set up by GetKernelSize().
479 * (elf_ptr_t)(uintptr_t) double-casting is needed because in some cases elf_ptr_t is an UQUAD,
480 * while in most cases it's a pointer (see dos/elf.h).
482 int LoadKernel(struct ELFNode
*FirstELF
, void *ptr_ro
, void *ptr_rw
, char *tracker_p
, uintptr_t DefSysBase
,
483 void **kick_end
, kernel_entry_fun_t
*kernel_entry
, struct ELF_ModuleInfo
**kernel_debug
)
487 unsigned char need_entry
= 1;
488 struct ELF_ModuleInfo_t
*mod
;
489 struct ELF_ModuleInfo_t
*prev_mod
= NULL
;
490 struct KernelBSS_t
*tracker
= (struct KernelBSS_t
*)tracker_p
;
492 kprintf("[ELF Loader] Loading kickstart...\n");
494 for (n
= FirstELF
; n
; n
= n
->Next
)
499 kprintf("[ELF Loader] Code %p, Data %p, Module %s...\n", ptr_ro
, ptr_rw
, n
->Name
);
501 file
= open_file(n
, &err
);
504 DisplayError("Failed to open file %s!\n", n
->Name
);
508 /* Iterate over the section header in order to load some hunks */
509 for (i
=0; i
< n
->eh
->shnum
; i
++)
511 struct sheader
*sh
= n
->sh
;
513 D(kprintf("[ELF Loader] Section %u... ", i
));
515 if ((sh
[i
].flags
& SHF_ALLOC
) || (sh
[i
].type
== SHT_STRTAB
) || (sh
[i
].type
== SHT_SYMTAB
))
517 /* Does the section require memory allcation? */
518 D(kprintf("Allocated section\n"));
520 if (sh
[i
].flags
& SHF_WRITE
)
522 ptr_rw
= load_hunk(file
, &sh
[i
], (void *)ptr_rw
, &tracker
);
525 DisplayError("%s: Error loading hunk %u!\n", n
->Name
, i
);
531 ptr_ro
= load_hunk(file
, &sh
[i
], (void *)ptr_ro
, &tracker
);
534 DisplayError("%s: Error loading hunk %u!\n", n
->Name
, i
);
539 /* Remember address of the first code section, this is our entry point */
540 if ((sh
[i
].flags
& SHF_EXECINSTR
) && need_entry
)
542 *kernel_entry
= (void *)(uintptr_t)sh
[i
].addr
;
546 D(else kprintf("Ignored\n");)
548 D(kprintf("[ELF Loader] Section address: %p, size: %lu\n", sh
[i
].addr
, sh
[i
].size
));
551 /* For every loaded section perform relocations */
552 D(kprintf("[ELF Loader] Relocating...\n"));
553 for (i
=0; i
< n
->eh
->shnum
; i
++)
555 struct sheader
*sh
= n
->sh
;
557 if ((sh
[i
].type
== AROS_ELF_REL
) && sh
[sh
[i
].info
].addr
)
559 sh
[i
].addr
= (elf_ptr_t
)(uintptr_t)load_block(file
, sh
[i
].offset
, sh
[i
].size
, &err
);
562 DisplayError("%s: Failed to load relocation section %u\n", n
->Name
, i
);
566 if (!relocate(n
->eh
, sh
, i
, (uintptr_t)DefSysBase
))
568 DisplayError("%s: Relocation error in section %u!\n", n
->Name
, i
);
572 free_block((void *)(uintptr_t)sh
[i
].addr
);
573 sh
[i
].addr
= (elf_ptr_t
)0;
579 D(kprintf("[ELF Loader] Adding module debug information...\n"));
581 /* Align our pointer */
582 ptr_ro
= (void *)(((uintptr_t)ptr_ro
+ sizeof(void *)) & ~(sizeof(void *) - 1));
584 /* Allocate module descriptor */
586 ptr_ro
+= sizeof(struct ELF_ModuleInfo_t
);
588 mod
->Type
= DEBUG_ELF
;
590 /* Copy ELF header */
591 mod
->eh
= (uintptr_t)ptr_ro
;
592 ptr_ro
= copy_data(n
->eh
, ptr_ro
, sizeof(struct elfheader
));
594 /* Copy section header */
595 mod
->sh
= (uintptr_t)ptr_ro
;
596 ptr_ro
= copy_data(n
->sh
, ptr_ro
, n
->eh
->shnum
* n
->eh
->shentsize
);
598 /* Copy module name */
599 mod
->Name
= (uintptr_t)ptr_ro
;
600 ptr_ro
= copy_data(n
->Name
, ptr_ro
, strlen(n
->Name
) + 1);
602 /* Link the module descriptor with previous one */
604 prev_mod
->Next
= (uintptr_t)mod
;
606 *kernel_debug
= (struct ELF_ModuleInfo
*)mod
;
613 /* Terminate the array of BSS sections */
617 /* Return end of kickstart read-only area if requested */