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
[SHINDEX(shrel
->link
)];
116 struct sheader
*toreloc
= &sh
[SHINDEX(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 DREL(kprintf("[ELF Loader] Undefined symbol '%s'\n", name
));
159 DREL(kprintf("[ELF Loader] COMMON symbol '%s'\n", name
));
163 if (SysBase_sym
== NULL
)
165 if (Strcmp(name
, "SysBase") == 0)
167 DREL(kprintf("[ELF Loader] got SysBase\n"));
172 if (SysBase_sym
== sym
)
176 SysBase_ptr
= DefSysBase
;
177 D(kprintf("[ELF Loader] SysBase pointer set to default %p\n", (void *)SysBase_ptr
));
187 s
= (uintptr_t)sh
[sym
->shindex
].addr
+ sym
->value
;
192 * The first global data symbol named SysBase becomes global SysBase.
193 * The idea behind: the first module (kernel.resource) contains global
194 * SysBase variable and all other modules are linked to it.
196 if (sym
->info
== ELF_S_INFO(STB_GLOBAL
, STT_OBJECT
))
198 if (Strcmp(name
, "SysBase") == 0)
201 D(kprintf("[ELF Loader] SysBase pointer set to %p\n", (void *)SysBase_ptr
));
207 DREL(kprintf("[ELF Loader] Relocating symbol %s type ", sym
->name
? name
: "<unknown>"));
208 switch (ELF_R_TYPE(rel
->info
))
211 case R_X86_64_64
: /* 64bit direct/absolute */
212 *(uint64_t *)p
= s
+ rel
->addend
;
215 case R_X86_64_PC32
: /* PC relative 32 bit signed */
216 *(uint32_t *)p
= s
+ rel
->addend
- (uintptr_t) p
;
220 *(uint32_t *)p
= (uint64_t)s
+ (uint64_t)rel
->addend
;
224 *(int32_t *)p
= (int64_t)s
+ (int64_t)rel
->addend
;
227 case R_X86_64_NONE
: /* No reloc */
231 case R_386_32
: /* 32bit absolute */
232 DREL(kprintf("R_386_32"));
236 case R_386_PC32
: /* 32bit PC relative */
237 DREL(kprintf("R_386_PC32"));
238 *p
+= (s
- (uintptr_t)p
);
242 DREL(kprintf("R_386_NONE"));
248 *p
= s
+ rel
->addend
;
252 *p
= s
+ rel
->addend
- (uint32_t)p
;
258 #if defined(__ppc__) || defined(__powerpc__)
260 *p
= s
+ rel
->addend
;
263 case R_PPC_ADDR16_LO
:
265 unsigned short *c
= (unsigned short *) p
;
266 *c
= (s
+ rel
->addend
) & 0xffff;
270 case R_PPC_ADDR16_HA
:
272 unsigned short *c
= (unsigned short *) p
;
273 uint32_t temp
= s
+ rel
->addend
;
275 if ((temp
& 0x8000) != 0)
282 unsigned short *c
= (unsigned short *) p
;
283 *c
= (s
+ rel
->addend
- (uint32_t)p
) & 0xffff;
289 unsigned short *c
= (unsigned short *) p
;
290 uint32_t temp
= s
+ rel
->addend
- (uint32_t)p
;
292 if ((temp
& 0x8000) != 0)
299 *p
|= (s
+ rel
->addend
- (uint32_t)p
) & 0x3fffffc;
303 *p
= s
+ rel
->addend
- (uint32_t)p
;
315 /* On ARM the 24 bit offset is shifted by 2 to the right */
316 signed long offset
= (*p
& 0x00ffffff) << 2;
317 /* If highest bit set, make offset negative */
318 if (offset
& 0x02000000)
319 offset
-= 0x04000000;
321 offset
+= s
- (uint32_t)p
;
325 *p
|= offset
& 0x00ffffff;
329 case R_ARM_MOVW_ABS_NC
:
332 signed long offset
= *p
;
333 offset
= ((offset
& 0xf0000) >> 4) | (offset
& 0xfff);
334 offset
= (offset
^ 0x8000) - 0x8000;
338 if (ELF_R_TYPE(rel
->info
) == R_ARM_MOVT_ABS
)
342 *p
|= ((offset
& 0xf000) << 4) | (offset
& 0x0fff);
354 kprintf("[ELF Loader] Unrecognized relocation type %d %ld\n", i
, (long)ELF_R_TYPE(rel
->info
));
357 DREL(kprintf(" -> %p\n", *p
));
362 int GetKernelSize(struct ELFNode
*FirstELF
, unsigned long *ro_size
, unsigned long *rw_size
, unsigned long *bss_size
)
365 unsigned long ksize
= 0;
366 unsigned long rwsize
= 0;
367 unsigned long bsize
= sizeof(struct KernelBSS_t
);
370 kprintf("[ELF Loader] Calculating kickstart size...\n");
372 for (n
= FirstELF
; n
; n
= n
->Next
)
378 D(kprintf("[ELF Loader] Checking file %s\n", n
->Name
));
380 file
= open_file(n
, &err
);
383 DisplayError("Failed to open file %s!\n", n
->Name
);
387 /* Check the header of ELF file */
388 n
->eh
= load_block(file
, 0, sizeof(struct elfheader
), &err
);
391 errstr
= "Failed to read file header";
395 errstr
= check_header(n
->eh
);
398 n
->sh
= load_block(file
, n
->eh
->shoff
, n
->eh
->shnum
* n
->eh
->shentsize
, &err
);
401 errstr
= "Failed to read section headers";
409 DisplayError("%s: %s\n", n
->Name
, errstr
);
414 * Debug data for the module includes:
415 * - Module descriptor (struct ELF_ModuleInfo_t)
417 * - ELF section header
419 * - One empty pointer for alignment
421 ksize
+= (sizeof(struct ELF_ModuleInfo_t
) + sizeof(struct elfheader
) + n
->eh
->shnum
* n
->eh
->shentsize
+
422 strlen(n
->Name
) + sizeof(void *));
424 /* Go through all sections and calculate kernel size */
425 for(i
= 0; i
< n
->eh
->shnum
; i
++)
427 /* Ignore sections with zero lengths */
433 * - Actual code and data (allocated sections)
434 * - String tables (for debug data)
435 * - Symbol tables (for debug data)
437 if ((n
->sh
[i
].flags
& SHF_ALLOC
) || (n
->sh
[i
].type
== SHT_STRTAB
) || (n
->sh
[i
].type
== SHT_SYMTAB
))
439 /* Add maximum space for alignment */
440 unsigned long s
= n
->sh
[i
].size
+ n
->sh
[i
].addralign
- 1;
442 if (n
->sh
[i
].flags
& SHF_WRITE
)
447 if (n
->sh
[i
].type
== SHT_NOBITS
)
448 bsize
+= sizeof(struct KernelBSS_t
);
459 kprintf("[ELF Loader] Code %lu bytes, data %lu bytes, BSS array %lu bytes\n", ksize
, rwsize
, bsize
);
465 * This function loads the listed modules.
466 * It expects that ELF and section header pointers in the list are already set up by GetKernelSize().
468 * (elf_ptr_t)(uintptr_t) double-casting is needed because in some cases elf_ptr_t is an UQUAD,
469 * while in most cases it's a pointer (see dos/elf.h).
471 int LoadKernel(struct ELFNode
*FirstELF
, void *ptr_ro
, void *ptr_rw
, void *tracker
, uintptr_t DefSysBase
,
472 void **kick_end
, kernel_entry_fun_t
*kernel_entry
, struct ELF_ModuleInfo
**kernel_debug
)
476 unsigned char need_entry
= 1;
477 struct ELF_ModuleInfo_t
*mod
;
478 struct ELF_ModuleInfo_t
*prev_mod
= NULL
;
480 kprintf("[ELF Loader] Loading kickstart...\n");
482 for (n
= FirstELF
; n
; n
= n
->Next
)
487 kprintf("[ELF Loader] Code %p, Data %p, Module %s...\n", ptr_ro
, ptr_rw
, n
->Name
);
489 file
= open_file(n
, &err
);
492 DisplayError("Failed to open file %s!\n", n
->Name
);
496 /* Iterate over the section header in order to load some hunks */
497 for (i
=0; i
< n
->eh
->shnum
; i
++)
499 struct sheader
*sh
= n
->sh
;
501 D(kprintf("[ELF Loader] Section %u... ", i
));
503 if ((sh
[i
].flags
& SHF_ALLOC
) || (sh
[i
].type
== SHT_STRTAB
) || (sh
[i
].type
== SHT_SYMTAB
))
505 /* Does the section require memory allcation? */
506 D(kprintf("Allocated section\n"));
508 if (sh
[i
].flags
& SHF_WRITE
)
510 ptr_rw
= load_hunk(file
, &sh
[i
], (void *)ptr_rw
, (struct KernelBSS_t
**)&tracker
);
513 DisplayError("%s: Error loading hunk %u!\n", n
->Name
, i
);
519 ptr_ro
= load_hunk(file
, &sh
[i
], (void *)ptr_ro
, (struct KernelBSS_t
**)&tracker
);
522 DisplayError("%s: Error loading hunk %u!\n", n
->Name
, i
);
527 /* Remember address of the first code section, this is our entry point */
528 if ((sh
[i
].flags
& SHF_EXECINSTR
) && need_entry
)
530 *kernel_entry
= (void *)(uintptr_t)sh
[i
].addr
;
534 D(else kprintf("Ignored\n");)
536 D(kprintf("[ELF Loader] Section address: %p, size: %lu\n", sh
[i
].addr
, sh
[i
].size
));
539 /* For every loaded section perform relocations */
540 D(kprintf("[ELF Loader] Relocating...\n"));
541 for (i
=0; i
< n
->eh
->shnum
; i
++)
543 struct sheader
*sh
= n
->sh
;
545 if ((sh
[i
].type
== AROS_ELF_REL
) && sh
[sh
[i
].info
].addr
)
547 sh
[i
].addr
= (elf_ptr_t
)(uintptr_t)load_block(file
, sh
[i
].offset
, sh
[i
].size
, &err
);
550 DisplayError("%s: Failed to load relocation section %u\n", n
->Name
, i
);
554 if (!relocate(n
->eh
, sh
, i
, (uintptr_t)DefSysBase
))
556 DisplayError("%s: Relocation error in section %u!\n", n
->Name
, i
);
560 free_block((void *)(uintptr_t)sh
[i
].addr
);
561 sh
[i
].addr
= (elf_ptr_t
)0;
567 D(kprintf("[ELF Loader] Adding module debug information...\n"));
569 /* Align our pointer */
570 ptr_ro
= (void *)(((uintptr_t)ptr_ro
+ sizeof(void *)) & ~(sizeof(void *) - 1));
572 /* Allocate module descriptor */
574 ptr_ro
+= sizeof(struct ELF_ModuleInfo_t
);
576 mod
->Type
= DEBUG_ELF
;
578 /* Copy ELF header */
579 mod
->eh
= (uintptr_t)ptr_ro
;
580 ptr_ro
= copy_data(n
->eh
, ptr_ro
, sizeof(struct elfheader
));
582 /* Copy section header */
583 mod
->sh
= (uintptr_t)ptr_ro
;
584 ptr_ro
= copy_data(n
->sh
, ptr_ro
, n
->eh
->shnum
* n
->eh
->shentsize
);
586 /* Copy module name */
587 mod
->Name
= (uintptr_t)ptr_ro
;
588 ptr_ro
= copy_data(n
->Name
, ptr_ro
, strlen(n
->Name
) + 1);
590 /* Link the module descriptor with previous one */
592 prev_mod
->Next
= (uintptr_t)mod
;
594 *kernel_debug
= (struct ELF_ModuleInfo
*)mod
;
601 /* Terminate the array of BSS sections */
602 ((struct KernelBSS_t
*)tracker
)->addr
= 0;
603 ((struct KernelBSS_t
*)tracker
)->len
= 0;
605 /* Return end of kickstart read-only area if requested */