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
); }
24 #include <libraries/debug.h>
26 #include <elfloader.h>
33 /* Use own definitions because we may be compiled as 32-bit code but build structures for 64-bit code */
34 struct ELF_ModuleInfo_t
39 unsigned short Pad0
; /* On i386 we have different alignment, so do explicit padding */
47 /* Our own definition of struct KernelBSS, to avoid excessive castings */
54 static elf_uintptr_t SysBase_ptr
= 0;
57 * Test for correct ELF header here
59 static char *check_header(struct elfheader
*eh
)
61 if (eh
->ident
[0] != 0x7f || eh
->ident
[1] != 'E' ||
62 eh
->ident
[2] != 'L' || eh
->ident
[3] != 'F')
63 return "Not a ELF file";
65 if (eh
->type
!= ET_REL
|| eh
->machine
!= AROS_ELF_MACHINE
)
66 return "Wrong object type or wrong architecture";
73 * Get the memory for chunk and load it
75 static void *load_hunk(void *file
, struct sheader
*sh
, void *addr
, struct KernelBSS_t
**bss_tracker
)
79 /* empty chunk? Who cares :) */
83 D(kprintf("[ELF Loader] Chunk (%ld bytes, align=%ld (%p) @ ", sh
->size
, sh
->addralign
, (void *)sh
->addralign
));
84 align
= sh
->addralign
- 1;
85 addr
= (char *)(((uintptr_t)addr
+ align
) & ~align
);
87 D(kprintf("%p\n", addr
));
88 sh
->addr
= (elf_ptr_t
)(uintptr_t)addr
;
90 /* copy block of memory from ELF file if it exists */
91 if (sh
->type
!= SHT_NOBITS
)
93 if (read_block(file
, sh
->offset
, (void *)(uintptr_t)sh
->addr
, sh
->size
))
98 memset(addr
, 0, sh
->size
);
100 (*bss_tracker
)->addr
= (uintptr_t)addr
;
101 (*bss_tracker
)->len
= sh
->size
;
105 return addr
+ sh
->size
;
108 static void *copy_data(void *src
, void *addr
, uintptr_t len
)
110 memcpy(addr
, src
, len
);
114 /* Perform relocations of given section */
115 static int relocate(struct elfheader
*eh
, struct sheader
*sh
, long shrel_idx
, elf_uintptr_t DefSysBase
)
117 struct sheader
*shrel
= &sh
[shrel_idx
];
118 struct sheader
*shsymtab
= &sh
[shrel
->link
];
119 struct sheader
*toreloc
= &sh
[shrel
->info
];
121 struct symbol
*symtab
= (struct symbol
*)(uintptr_t)shsymtab
->addr
;
122 struct relo
*rel
= (struct relo
*)(uintptr_t)shrel
->addr
;
123 /* Early cast to uintptr_t omits __udivdi3 call in x86-64 native bootstrap */
124 unsigned int numrel
= (uintptr_t)shrel
->size
/ (uintptr_t)shrel
->entsize
;
127 struct symbol
*SysBase_sym
= NULL
;
130 * Ignore relocs if the target section has no allocation. that can happen
131 * eg. with a .debug PROGBITS and a .rel.debug section
133 if (!(toreloc
->flags
& SHF_ALLOC
))
136 DREL(kprintf("[ELF Loader] performing %d relocations\n", numrel
));
138 for (i
=0; i
<numrel
; i
++, rel
++)
140 struct symbol
*sym
= &symtab
[ELF_R_SYM(rel
->info
)];
141 uintptr_t *p
= (void *)(uintptr_t)toreloc
->addr
+ rel
->offset
;
142 const char *name
= (const char *)(uintptr_t)sh
[shsymtab
->link
].addr
+ sym
->name
;
147 * R_ARM_V4BX are actually special marks for the linker.
148 * They even never have a target (shindex == SHN_UNDEF),
149 * so we simply ignore them before doing any checks.
151 if (ELF_R_TYPE(rel
->info
) == R_ARM_V4BX
)
155 switch (sym
->shindex
)
158 if (Strcmp(name
, "SysBase") == 0) {
161 SysBase_ptr
= DefSysBase
;
162 D(kprintf("[ELF Loader] SysBase pointer set to default %p\n", (void *)SysBase_ptr
));
167 kprintf("[ELF Loader] Undefined symbol '%s'\n", name
);
173 kprintf("[ELF Loader] COMMON symbol '%s'\n", name
);
177 if (SysBase_sym
== NULL
)
179 if (Strcmp(name
, "SysBase") == 0)
181 DREL(kprintf("[ELF Loader] got SysBase\n"));
186 if (SysBase_sym
== sym
)
190 SysBase_ptr
= DefSysBase
;
191 D(kprintf("[ELF Loader] SysBase pointer set to default %p\n", (void *)SysBase_ptr
));
201 s
= (uintptr_t)sh
[sym
->shindex
].addr
+ sym
->value
;
206 * The first global data symbol named SysBase becomes global SysBase.
207 * The idea behind: the first module (kernel.resource) contains global
208 * SysBase variable and all other modules are linked to it.
210 if (sym
->info
== ELF_S_INFO(STB_GLOBAL
, STT_OBJECT
))
212 if (Strcmp(name
, "SysBase") == 0)
215 D(kprintf("[ELF Loader] SysBase pointer set to %p\n", (void *)SysBase_ptr
));
221 DREL(kprintf("[ELF Loader] Relocating symbol %s type ", sym
->name
? name
: "<unknown>"));
222 switch (ELF_R_TYPE(rel
->info
))
225 case R_X86_64_64
: /* 64bit direct/absolute */
226 *(uint64_t *)p
= s
+ rel
->addend
;
229 case R_X86_64_PC32
: /* PC relative 32 bit signed */
230 *(uint32_t *)p
= s
+ rel
->addend
- (uintptr_t) p
;
234 *(uint32_t *)p
= (uint64_t)s
+ (uint64_t)rel
->addend
;
238 *(int32_t *)p
= (int64_t)s
+ (int64_t)rel
->addend
;
241 case R_X86_64_NONE
: /* No reloc */
245 case R_386_32
: /* 32bit absolute */
246 DREL(kprintf("R_386_32"));
250 case R_386_PC32
: /* 32bit PC relative */
251 DREL(kprintf("R_386_PC32"));
252 *p
+= (s
- (uintptr_t)p
);
256 DREL(kprintf("R_386_NONE"));
262 *p
= s
+ rel
->addend
;
266 *p
= s
+ rel
->addend
- (uint32_t)p
;
272 #if defined(__ppc__) || defined(__powerpc__)
274 *p
= s
+ rel
->addend
;
277 case R_PPC_ADDR16_LO
:
279 unsigned short *c
= (unsigned short *) p
;
280 *c
= (s
+ rel
->addend
) & 0xffff;
284 case R_PPC_ADDR16_HA
:
286 unsigned short *c
= (unsigned short *) p
;
287 uint32_t temp
= s
+ rel
->addend
;
289 if ((temp
& 0x8000) != 0)
296 unsigned short *c
= (unsigned short *) p
;
297 *c
= (s
+ rel
->addend
- (uint32_t)p
) & 0xffff;
303 unsigned short *c
= (unsigned short *) p
;
304 uint32_t temp
= s
+ rel
->addend
- (uint32_t)p
;
306 if ((temp
& 0x8000) != 0)
313 *p
|= (s
+ rel
->addend
- (uint32_t)p
) & 0x3fffffc;
317 *p
= s
+ rel
->addend
- (uint32_t)p
;
329 /* On ARM the 24 bit offset is shifted by 2 to the right */
330 signed long offset
= (*p
& 0x00ffffff) << 2;
331 /* If highest bit set, make offset negative */
332 if (offset
& 0x02000000)
333 offset
-= 0x04000000;
335 offset
+= s
- (uint32_t)p
;
339 *p
|= offset
& 0x00ffffff;
343 case R_ARM_MOVW_ABS_NC
:
346 signed long offset
= *p
;
347 offset
= ((offset
& 0xf0000) >> 4) | (offset
& 0xfff);
348 offset
= (offset
^ 0x8000) - 0x8000;
352 if (ELF_R_TYPE(rel
->info
) == R_ARM_MOVT_ABS
)
356 *p
|= ((offset
& 0xf000) << 4) | (offset
& 0x0fff);
368 kprintf("[ELF Loader] Unrecognized relocation type %d %ld\n", i
, (long)ELF_R_TYPE(rel
->info
));
371 DREL(kprintf(" -> %p\n", *p
));
376 int GetKernelSize(struct ELFNode
*FirstELF
, unsigned long *ro_size
, unsigned long *rw_size
, unsigned long *bss_size
)
379 unsigned long ksize
= 0;
380 unsigned long rwsize
= 0;
381 unsigned long bsize
= sizeof(struct KernelBSS_t
);
384 kprintf("[ELF Loader] Calculating kickstart size...\n");
386 for (n
= FirstELF
; n
; n
= n
->Next
)
392 D(kprintf("[ELF Loader] Checking file %s\n", n
->Name
));
394 file
= open_file(n
, &err
);
397 DisplayError("Failed to open file %s!\n", n
->Name
);
401 /* Check the header of ELF file */
402 n
->eh
= load_block(file
, 0, sizeof(struct elfheader
), &err
);
405 errstr
= "Failed to read file header";
409 errstr
= check_header(n
->eh
);
412 n
->sh
= load_block(file
, n
->eh
->shoff
, n
->eh
->shnum
* n
->eh
->shentsize
, &err
);
415 errstr
= "Failed to read section headers";
423 DisplayError("%s: %s\n", n
->Name
, errstr
);
428 * Debug data for the module includes:
429 * - Module descriptor (struct ELF_ModuleInfo_t)
431 * - ELF section header
433 * - One empty pointer for alignment
435 ksize
+= (sizeof(struct ELF_ModuleInfo_t
) + sizeof(struct elfheader
) + n
->eh
->shnum
* n
->eh
->shentsize
+
436 strlen(n
->Name
) + sizeof(void *));
438 /* Go through all sections and calculate kernel size */
439 for(i
= 0; i
< n
->eh
->shnum
; i
++)
441 /* Ignore sections with zero lengths */
447 * - Actual code and data (allocated sections)
448 * - String tables (for debug data)
449 * - Symbol tables (for debug data)
451 if ((n
->sh
[i
].flags
& SHF_ALLOC
) || (n
->sh
[i
].type
== SHT_STRTAB
) || (n
->sh
[i
].type
== SHT_SYMTAB
))
453 /* Add maximum space for alignment */
454 unsigned long s
= n
->sh
[i
].size
+ n
->sh
[i
].addralign
- 1;
456 if (n
->sh
[i
].flags
& SHF_WRITE
)
461 if (n
->sh
[i
].type
== SHT_NOBITS
)
462 bsize
+= sizeof(struct KernelBSS_t
);
473 kprintf("[ELF Loader] Code %lu bytes, data %lu bytes, BSS array %lu bytes\n", ksize
, rwsize
, bsize
);
479 * This function loads the listed modules.
480 * It expects that ELF and section header pointers in the list are already set up by GetKernelSize().
482 * (elf_ptr_t)(uintptr_t) double-casting is needed because in some cases elf_ptr_t is an UQUAD,
483 * while in most cases it's a pointer (see dos/elf.h).
485 int LoadKernel(struct ELFNode
*FirstELF
, void *ptr_ro
, void *ptr_rw
, char *tracker_p
, uintptr_t DefSysBase
,
486 void **kick_end
, kernel_entry_fun_t
*kernel_entry
, struct ELF_ModuleInfo
**kernel_debug
)
490 unsigned char need_entry
= 1;
491 struct ELF_ModuleInfo_t
*mod
;
492 struct ELF_ModuleInfo_t
*prev_mod
= NULL
;
493 struct KernelBSS_t
*tracker
= (struct KernelBSS_t
*)tracker_p
;
495 kprintf("[ELF Loader] Loading kickstart...\n");
497 for (n
= FirstELF
; n
; n
= n
->Next
)
502 kprintf("[ELF Loader] Code %p, Data %p, Module %s...\n", ptr_ro
, ptr_rw
, n
->Name
);
504 file
= open_file(n
, &err
);
507 DisplayError("Failed to open file %s!\n", n
->Name
);
511 /* Iterate over the section header in order to load some hunks */
512 for (i
=0; i
< n
->eh
->shnum
; i
++)
514 struct sheader
*sh
= n
->sh
;
516 D(kprintf("[ELF Loader] Section %u... ", i
));
518 if ((sh
[i
].flags
& SHF_ALLOC
) || (sh
[i
].type
== SHT_STRTAB
) || (sh
[i
].type
== SHT_SYMTAB
))
520 /* Does the section require memory allcation? */
521 D(kprintf("Allocated section\n"));
523 if (sh
[i
].flags
& SHF_WRITE
)
525 ptr_rw
= load_hunk(file
, &sh
[i
], (void *)ptr_rw
, &tracker
);
528 DisplayError("%s: Error loading hunk %u!\n", n
->Name
, i
);
534 ptr_ro
= load_hunk(file
, &sh
[i
], (void *)ptr_ro
, &tracker
);
537 DisplayError("%s: Error loading hunk %u!\n", n
->Name
, i
);
542 /* Remember address of the first code section, this is our entry point */
543 if ((sh
[i
].flags
& SHF_EXECINSTR
) && need_entry
)
545 *kernel_entry
= (void *)(uintptr_t)sh
[i
].addr
;
549 D(else kprintf("Ignored\n");)
551 D(kprintf("[ELF Loader] Section address: %p, size: %lu\n", sh
[i
].addr
, sh
[i
].size
));
554 /* For every loaded section perform relocations */
555 D(kprintf("[ELF Loader] Relocating...\n"));
556 for (i
=0; i
< n
->eh
->shnum
; i
++)
558 struct sheader
*sh
= n
->sh
;
560 if ((sh
[i
].type
== AROS_ELF_REL
) && sh
[sh
[i
].info
].addr
)
562 sh
[i
].addr
= (elf_ptr_t
)(uintptr_t)load_block(file
, sh
[i
].offset
, sh
[i
].size
, &err
);
565 DisplayError("%s: Failed to load relocation section %u\n", n
->Name
, i
);
569 if (!relocate(n
->eh
, sh
, i
, (uintptr_t)DefSysBase
))
571 DisplayError("%s: Relocation error in section %u!\n", n
->Name
, i
);
575 free_block((void *)(uintptr_t)sh
[i
].addr
);
576 sh
[i
].addr
= (elf_ptr_t
)0;
582 D(kprintf("[ELF Loader] Adding module debug information...\n"));
584 /* Align our pointer */
585 ptr_ro
= (void *)(((uintptr_t)ptr_ro
+ sizeof(void *)) & ~(sizeof(void *) - 1));
587 /* Allocate module descriptor */
589 ptr_ro
+= sizeof(struct ELF_ModuleInfo_t
);
591 mod
->Type
= DEBUG_ELF
;
593 /* Copy ELF header */
594 mod
->eh
= (uintptr_t)ptr_ro
;
595 ptr_ro
= copy_data(n
->eh
, ptr_ro
, sizeof(struct elfheader
));
597 /* Copy section header */
598 mod
->sh
= (uintptr_t)ptr_ro
;
599 ptr_ro
= copy_data(n
->sh
, ptr_ro
, n
->eh
->shnum
* n
->eh
->shentsize
);
601 /* Copy module name */
602 mod
->Name
= (uintptr_t)ptr_ro
;
603 ptr_ro
= copy_data(n
->Name
, ptr_ro
, strlen(n
->Name
) + 1);
605 /* Link the module descriptor with previous one */
607 prev_mod
->Next
= (uintptr_t)mod
;
609 *kernel_debug
= (struct ELF_ModuleInfo
*)mod
;
616 /* Terminate the array of BSS sections */
620 /* Return end of kickstart read-only area if requested */