2 Copyright (C) 2006-2019 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 an ELF file";
65 if (eh
->type
!= ET_REL
|| eh
->machine
!= AROS_ELF_MACHINE
)
66 return "Object of the wrong type or 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 *)(uintptr_t)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 symbol set to default %p\n", (void *)(uintptr_t)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 symbol set to default %p\n", (void *)(uintptr_t)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 symbol set to %p\n", (void *)(uintptr_t)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
;
230 case R_X86_64_PC32
: /* PC relative 32 bit signed */
231 *(uint32_t *)p
= s
+ rel
->addend
- (uintptr_t) p
;
235 *(uint32_t *)p
= (uint64_t)s
+ (uint64_t)rel
->addend
;
239 *(int32_t *)p
= (int64_t)s
+ (int64_t)rel
->addend
;
242 case R_X86_64_NONE
: /* No reloc */
246 case R_386_32
: /* 32bit absolute */
247 DREL(kprintf("R_386_32"));
251 case R_386_PC32
: /* 32bit PC relative */
252 DREL(kprintf("R_386_PC32"));
253 *p
+= (s
- (uintptr_t)p
);
257 DREL(kprintf("R_386_NONE"));
263 *p
= s
+ rel
->addend
;
267 *p
= s
+ rel
->addend
- (uint32_t)p
;
273 #if defined(__ppc__) || defined(__powerpc__)
275 *p
= s
+ rel
->addend
;
278 case R_PPC_ADDR16_LO
:
280 unsigned short *c
= (unsigned short *) p
;
281 *c
= (s
+ rel
->addend
) & 0xffff;
285 case R_PPC_ADDR16_HA
:
287 unsigned short *c
= (unsigned short *) p
;
288 uint32_t temp
= s
+ rel
->addend
;
290 if ((temp
& 0x8000) != 0)
297 unsigned short *c
= (unsigned short *) p
;
298 *c
= (s
+ rel
->addend
- (uint32_t)p
) & 0xffff;
304 unsigned short *c
= (unsigned short *) p
;
305 uint32_t temp
= s
+ rel
->addend
- (uint32_t)p
;
307 if ((temp
& 0x8000) != 0)
314 *p
|= (s
+ rel
->addend
- (uint32_t)p
) & 0x3fffffc;
318 *p
= s
+ rel
->addend
- (uint32_t)p
;
330 /* On ARM the 24 bit offset is shifted by 2 to the right */
331 signed long offset
= (*p
& 0x00ffffff) << 2;
332 /* If highest bit set, make offset negative */
333 if (offset
& 0x02000000)
334 offset
-= 0x04000000;
336 offset
+= s
- (uint32_t)p
;
340 *p
|= offset
& 0x00ffffff;
344 case R_ARM_MOVW_ABS_NC
:
347 signed long offset
= *p
;
348 offset
= ((offset
& 0xf0000) >> 4) | (offset
& 0xfff);
349 offset
= (offset
^ 0x8000) - 0x8000;
353 if (ELF_R_TYPE(rel
->info
) == R_ARM_MOVT_ABS
)
357 *p
|= ((offset
& 0xf000) << 4) | (offset
& 0x0fff);
369 kprintf("[ELF Loader] Unknown relocation #%d type %ld\n", i
, (long)ELF_R_TYPE(rel
->info
));
372 DREL(kprintf(" -> %p\n", *p
));
377 int GetKernelSize(struct ELFNode
*FirstELF
, unsigned long *ro_size
, unsigned long *rw_size
, unsigned long *bss_size
)
380 unsigned long ksize
= 0;
381 unsigned long rwsize
= 0;
382 unsigned long bsize
= sizeof(struct KernelBSS_t
);
385 kprintf("[ELF Loader] Calculating kickstart size...\n");
387 for (n
= FirstELF
; n
; n
= n
->Next
)
393 D(kprintf("[ELF Loader] Checking file %s\n", n
->Name
));
395 file
= open_file(n
, &err
);
398 DisplayError("Failed to open file %s!\n", n
->Name
);
402 /* Check the header of ELF file */
403 n
->eh
= load_block(file
, 0, sizeof(struct elfheader
), &err
);
406 errstr
= "Failed to read file header";
410 errstr
= check_header(n
->eh
);
413 n
->sh
= load_block(file
, n
->eh
->shoff
, n
->eh
->shnum
* n
->eh
->shentsize
, &err
);
416 errstr
= "Failed to read section header(s)";
424 DisplayError("%s: %s\n", n
->Name
, errstr
);
429 * Debug data for the module includes:
430 * - Module descriptor (struct ELF_ModuleInfo_t)
432 * - ELF section header
434 * - One empty pointer for alignment
436 ksize
+= (sizeof(struct ELF_ModuleInfo_t
) + sizeof(struct elfheader
) + n
->eh
->shnum
* n
->eh
->shentsize
+
437 strlen(n
->Name
) + sizeof(void *));
439 /* Go through all sections and calculate kernel size */
440 for(i
= 0; i
< n
->eh
->shnum
; i
++)
442 /* Ignore sections with zero lengths */
448 * - Actual code and data (allocated sections)
449 * - String tables (for debug data)
450 * - Symbol tables (for debug data)
452 if ((n
->sh
[i
].flags
& SHF_ALLOC
) || (n
->sh
[i
].type
== SHT_STRTAB
) || (n
->sh
[i
].type
== SHT_SYMTAB
))
454 /* Add maximum space for alignment */
455 unsigned long s
= n
->sh
[i
].size
+ n
->sh
[i
].addralign
- 1;
457 if (n
->sh
[i
].flags
& SHF_WRITE
)
462 if (n
->sh
[i
].type
== SHT_NOBITS
)
463 bsize
+= sizeof(struct KernelBSS_t
);
474 kprintf("[ELF Loader] Code %lu bytes, data %lu bytes, BSS array %lu bytes\n", ksize
, rwsize
, bsize
);
480 * This function loads the listed modules.
481 * It expects that ELF and section header pointers in the list are already set up by GetKernelSize().
483 * (elf_ptr_t)(uintptr_t) double-casting is needed because in some cases elf_ptr_t is an UQUAD,
484 * while in most cases it's a pointer (see dos/elf.h).
486 int LoadKernel(struct ELFNode
*FirstELF
, void *ptr_ro
, void *ptr_rw
, char *tracker_p
, uintptr_t DefSysBase
,
487 void **kick_end
, kernel_entry_fun_t
*kernel_entry
, struct ELF_ModuleInfo
**kernel_debug
)
491 unsigned char need_entry
= 1;
492 struct ELF_ModuleInfo_t
*mod
;
493 struct ELF_ModuleInfo_t
*prev_mod
= NULL
;
494 struct KernelBSS_t
*tracker
= (struct KernelBSS_t
*)tracker_p
;
496 kprintf("[ELF Loader] Loading kickstart...\n");
498 for (n
= FirstELF
; n
; n
= n
->Next
)
503 kprintf("[ELF Loader] Code %p, Data %p, Module %s...\n", ptr_ro
, ptr_rw
, n
->Name
);
505 file
= open_file(n
, &err
);
508 DisplayError("Failed to open file %s!\n", n
->Name
);
512 /* Iterate over the section header in order to load some hunks */
513 for (i
=0; i
< n
->eh
->shnum
; i
++)
515 struct sheader
*sh
= n
->sh
;
517 D(kprintf("[ELF Loader] Section %u... ", i
));
519 if ((sh
[i
].flags
& SHF_ALLOC
) || (sh
[i
].type
== SHT_STRTAB
) || (sh
[i
].type
== SHT_SYMTAB
))
521 /* Does the section require memory allcation? */
522 D(kprintf("Allocated section\n"));
524 if (sh
[i
].flags
& SHF_WRITE
)
526 ptr_rw
= load_hunk(file
, &sh
[i
], (void *)ptr_rw
, &tracker
);
529 DisplayError("%s: Error loading hunk %u!\n", n
->Name
, i
);
535 ptr_ro
= load_hunk(file
, &sh
[i
], (void *)ptr_ro
, &tracker
);
538 DisplayError("%s: Error loading hunk %u!\n", n
->Name
, i
);
543 /* Remember address of the first code section, this is our entry point */
544 if ((sh
[i
].flags
& SHF_EXECINSTR
) && need_entry
)
546 *kernel_entry
= (void *)(uintptr_t)sh
[i
].addr
;
550 D(else kprintf("Ignored\n");)
552 D(kprintf("[ELF Loader] Section address: %p, size: %lu\n", sh
[i
].addr
, sh
[i
].size
));
555 /* For every loaded section perform relocations */
556 D(kprintf("[ELF Loader] Relocating...\n"));
557 for (i
=0; i
< n
->eh
->shnum
; i
++)
559 struct sheader
*sh
= n
->sh
;
561 if ((sh
[i
].type
== AROS_ELF_REL
) && sh
[sh
[i
].info
].addr
)
563 sh
[i
].addr
= (elf_ptr_t
)(uintptr_t)load_block(file
, sh
[i
].offset
, sh
[i
].size
, &err
);
566 DisplayError("%s: Failed to load relocation section %u\n", n
->Name
, i
);
570 if (!relocate(n
->eh
, sh
, i
, (uintptr_t)DefSysBase
))
572 DisplayError("%s: Relocation error in section %u!\n", n
->Name
, i
);
576 free_block((void *)(uintptr_t)sh
[i
].addr
);
577 sh
[i
].addr
= (elf_ptr_t
)0;
583 D(kprintf("[ELF Loader] Adding module debug information...\n"));
585 /* Align our pointer */
586 ptr_ro
= (void *)(((uintptr_t)ptr_ro
+ sizeof(void *)) & ~(sizeof(void *) - 1));
588 /* Allocate module descriptor */
590 ptr_ro
+= sizeof(struct ELF_ModuleInfo_t
);
592 mod
->Type
= DEBUG_ELF
;
594 /* Copy ELF header */
595 mod
->eh
= (uintptr_t)ptr_ro
;
596 ptr_ro
= copy_data(n
->eh
, ptr_ro
, sizeof(struct elfheader
));
598 /* Copy section header */
599 mod
->sh
= (uintptr_t)ptr_ro
;
600 ptr_ro
= copy_data(n
->sh
, ptr_ro
, n
->eh
->shnum
* n
->eh
->shentsize
);
602 /* Copy module name */
603 mod
->Name
= (uintptr_t)ptr_ro
;
604 ptr_ro
= copy_data(n
->Name
, ptr_ro
, strlen(n
->Name
) + 1);
606 /* Link the module descriptor with previous one */
608 prev_mod
->Next
= (uintptr_t)mod
;
610 *kernel_debug
= (struct ELF_ModuleInfo
*)mod
;
617 /* Terminate the array of BSS sections */
621 /* Return end of kickstart read-only area if requested */