2 Copyright (C) 2006 The AROS Development Team. All rights reserved.
5 Desc: ELF64 loader extracted from our internal_load_seg_elf in dos.library.
12 #include "../include/aros/kernel.h"
13 #include "elfloader.h"
15 #include "bootstrap.h"
19 * This two pointers are used by the ELF loader to claim for memory ranges for both
20 * the RW sections (.data, .bss and such) and RO sections (.text, .rodata....) of executable.
21 * Keeping both areas of memory separate reduces the memory waste when more modules are
22 * loaded. Moreover, the whole RO range may be marked for MMU as read-only at once.
24 char *ptr_ro
= (char*)KERNEL_TARGET_ADDRESS
;
25 char *ptr_rw
= (char*)KERNEL_TARGET_ADDRESS
;
27 unsigned long long addr
;
28 unsigned long long len
;
36 void *kernel_highest()
41 void set_base_address(void *ptr
, void *tracker
)
43 ptr_ro
= ptr_rw
= ptr
;
44 bss_tracker
= (struct _bss_tracker
*)tracker
;
48 * read_block function copies the range of memory within ELF file to any specified location.
50 static int read_block(void *file
, long offset
, void *dest
, long length
)
52 __bs_memcpy(dest
, (void *)((long)file
+ offset
), length
);
57 * load_block returns a pointer to the memory location within ELF file.
59 static void *load_block(void *file
, long offset
, long length
)
61 return (void*)((long)file
+ offset
);
65 * Test for correct ELF header here
67 static int check_header(struct elfheader
*eh
)
71 eh
->ident
[0] != 0x7f ||
72 eh
->ident
[1] != 'E' ||
73 eh
->ident
[2] != 'L' ||
77 kprintf("[ELF Loader] Not an ELF object\n");
81 if (eh
->type
!= ET_REL
|| eh
->machine
!= EM_X86_64
)
83 kprintf("[ELF Loader] Wrong object type or wrong architecture\n");
90 * Get the memory for chunk and load it
92 static int load_hunk(void *file
, struct sheader
*sh
)
96 /* empty chunk? Who cares :) */
100 /* Allocate a chunk with write access - take aligned memory beneath the RO kernel */
101 if (sh
->flags
& SHF_WRITE
)
103 D(kprintf("[ELF Loader] RW chunk (%d bytes, align=%d) @ ", (unsigned int)sh
->size
, (unsigned int)sh
->addralign
));
104 ptr
= (void*)(((unsigned long)ptr_rw
- (unsigned long)sh
->size
- (unsigned long)sh
->addralign
+ 1) & ~((unsigned long)sh
->addralign
-1));
109 /* Read-Only mode? Get the memory from the kernel space, align it accorting to the demand */
110 D(kprintf("[ELF Loader] RO chunk (%d bytes, align=%d) @ ", (unsigned int)sh
->size
, (unsigned int)sh
->addralign
));
111 ptr_ro
= (char *)(((unsigned long)ptr_ro
+ (unsigned long)sh
->addralign
- 1) & ~((unsigned long)sh
->addralign
-1));
113 ptr_ro
= ptr_ro
+ sh
->size
;
115 D(kprintf("%p\n", (unsigned int)ptr
));
117 sh
->addr
= (long)ptr
;
119 /* copy block of memory from ELF file if it exists */
120 if (sh
->type
!= SHT_NOBITS
)
121 return read_block(file
, sh
->offset
, (void *)((unsigned long)sh
->addr
), sh
->size
);
124 __bs_bzero(ptr
, sh
->size
);
125 bss_tracker
->addr
= KERNEL_OFFSET
| (unsigned long long)ptr
;
126 bss_tracker
->len
= sh
->size
;
128 bss_tracker
->addr
= NULL
;
129 bss_tracker
->len
= 0;
135 /* Perform relocations of given section */
136 static int relocate(struct elfheader
*eh
, struct sheader
*sh
, long shrel_idx
, unsigned long long virt
)
138 struct sheader
*shrel
= &sh
[shrel_idx
];
139 struct sheader
*shsymtab
= &sh
[shrel
->link
];
140 struct sheader
*toreloc
= &sh
[shrel
->info
];
142 struct symbol
*symtab
= (struct symbol
*)((unsigned long)shsymtab
->addr
);
143 struct relo
*rel
= (struct relo
*)((unsigned long)shrel
->addr
);
144 char *section
= (char *)((unsigned long)toreloc
->addr
);
146 unsigned int numrel
= (unsigned long)shrel
->size
/ (unsigned long)shrel
->entsize
;
149 struct symbol
*SysBase_sym
= (void*)0;
151 D(kprintf("[ELF Loader] performing %d relocations, target address %p%p\n",
152 numrel
, (unsigned long)(virt
>> 32), (unsigned long)virt
));
154 for (i
=0; i
<numrel
; i
++, rel
++)
156 struct symbol
*sym
= &symtab
[ELF64_R_SYM(rel
->info
)];
157 unsigned long *p
= (unsigned long *)§ion
[rel
->offset
];
158 unsigned long long s
;
160 switch (sym
->shindex
)
163 D(kprintf("[ELF Loader] Undefined symbol '%s' while relocating the section '%s'\n",
164 (char *)((unsigned long)sh
[shsymtab
->link
].addr
) + sym
->name
,
165 (char *)((unsigned long)sh
[eh
->shstrndx
].addr
) + toreloc
->name
));
169 D(kprintf("[ELF Loader] COMMON symbol '%s' while relocating the section '%s'\n",
170 (char *)((unsigned long)sh
[shsymtab
->link
].addr
) + sym
->name
,
171 (char *)((unsigned long)sh
[eh
->shstrndx
].addr
) + toreloc
->name
));
176 if (SysBase_sym
== (void*)0)
178 if (__bs_strncmp((char *)((unsigned long)sh
[shsymtab
->link
].addr
) + sym
->name
, "SysBase", 8) == 0)
187 if (SysBase_sym
== sym
)
189 SysBase_yes
: s
= (unsigned long long)4ULL;
192 SysBase_no
: s
= sym
->value
;
196 s
= (unsigned long long)sh
[sym
->shindex
].addr
+ virt
+ sym
->value
;
201 switch (ELF64_R_TYPE(rel
->info
))
203 case R_X86_64_64
: /* 64bit direct/absolute */
204 *(unsigned long long *)p
= s
+ rel
->addend
;// + virt;
207 case R_X86_64_PC32
: /* PC relative 32 bit signed */
208 *p
= s
+ rel
->addend
- (unsigned long)((unsigned long long)p
+ virt
);
212 *(unsigned long *)p
= (unsigned long long)s
+ (unsigned long long)rel
->addend
;// + virt;
216 *(signed long *)p
= (signed long long)s
+ (signed long long)rel
->addend
;// + virt;
219 case R_X86_64_NONE
: /* No reloc */
223 kprintf("[ELF Loader] Unrecognized relocation type %d %d\n", i
, (unsigned int)ELF64_R_TYPE(rel
->info
));
230 void load_elf_file(void *file
, unsigned long long virt
)
235 int addr_displayed
= 0;
237 D(kprintf("[ELF Loader] Loading ELF module from address %p\n", (unsigned int)file
));
239 /* Check the header of ELF file */
242 !read_block(file
, 0, &eh
, sizeof(eh
)) ||
243 !check_header(&eh
) ||
244 !(sh
= load_block(file
, eh
.shoff
, eh
.shnum
* eh
.shentsize
))
247 kprintf("[ELF Loader] Wrong module header, aborting.\n");
251 /* Iterate over the section header in order to prepare memory and eventually load some hunks */
252 for (i
=0; i
< eh
.shnum
; i
++)
254 /* Load the symbol and string tables */
255 if (sh
[i
].type
== SHT_SYMTAB
|| sh
[i
].type
== SHT_STRTAB
)
257 sh
[i
].addr
= (unsigned long)load_block(file
, sh
[i
].offset
, sh
[i
].size
);
259 /* Does the section require memoy allcation? */
260 else if (sh
[i
].flags
& SHF_ALLOC
)
262 /* Yup, it does. Load the hunk */
263 if (!load_hunk(file
, &sh
[i
]))
265 kprintf("[ELF Loader] Error at loading of the hunk!\n");
267 else if (!addr_displayed
)
269 kprintf("%p", sh
[i
].addr
);
275 /* For every loaded section perform the relocations */
276 for (i
=0; i
< eh
.shnum
; i
++)
278 if (sh
[i
].type
== SHT_RELA
&& sh
[sh
[i
].info
].addr
)
280 sh
[i
].addr
= (unsigned long)load_block(file
, sh
[i
].offset
, sh
[i
].size
);
281 if (!sh
[i
].addr
|| !relocate(&eh
, sh
, i
, virt
))
283 kprintf("[ELF Loader] Relocation error!\n");