2 Copyright (C) 2006-2009 The AROS Development Team. All rights reserved.
5 Desc: ELF32 loader extracted from our internal_load_seg_elf in dos.library.
10 #include "elfloader32.h"
18 #define kprintf printf
21 * These two pointers are used by the ELF loader to claim for memory ranges for both
22 * the RW sections (.data, .bss and such) and RO sections (.text, .rodata....) of executable.
38 void *kernel_highest()
43 void set_base_address(void *tracker
, void ** sysbaseaddr
)
45 D(printf("[ELF Loader] set_base_address %p %p\n", tracker
, sysbaseaddr
));
46 bss_tracker
= (struct _bss_tracker
*)tracker
;
47 SysBaseAddr
= sysbaseaddr
;
51 * read_block interface. we want to read from files here
53 static int read_block(void *file
, long offset
, void *dest
, long length
)
55 fseek(file
, offset
, SEEK_SET
);
56 fread(dest
,(size_t)length
, 1, file
);
61 * load_block also allocates teh memory
63 static void *load_block(void *file
, long offset
, long length
)
65 void * dest
= malloc(length
);
66 fseek(file
, offset
, SEEK_SET
);
67 fread(dest
, (size_t)length
, 1, file
);
71 static void free_block(void * block
)
78 * Test for correct ELF header here
80 static int check_header(struct elfheader
*eh
)
84 eh
->ident
[0] != 0x7f ||
85 eh
->ident
[1] != 'E' ||
86 eh
->ident
[2] != 'L' ||
90 D(kprintf("[ELF Loader] Not an ELF object\n"));
94 if (eh
->type
!= ET_REL
|| eh
->machine
!= EM_386
)
96 D(kprintf("[ELF Loader] Wrong object type or wrong architecture\n"));
103 * Get the memory for chunk and load it
105 static int load_hunk(void *file
, struct sheader
*sh
)
109 /* empty chunk? Who cares :) */
113 D(kprintf("[ELF Loader] Chunk (%d bytes, align=%d) @ ", (unsigned int)sh
->size
, (unsigned int)sh
->addralign
));
114 ptr_ro
= (char *)(((unsigned long)ptr_ro
+ (unsigned long)sh
->addralign
- 1) & ~((unsigned long)sh
->addralign
-1));
116 ptr_ro
= ptr_ro
+ sh
->size
;
117 D(kprintf("%p\n", (unsigned int)ptr
));
121 /* copy block of memory from ELF file if it exists */
122 if (sh
->type
!= SHT_NOBITS
)
123 return read_block(file
, sh
->offset
, (void *)((unsigned long)sh
->addr
), sh
->size
);
126 memset(ptr
, 0, sh
->size
);
127 bss_tracker
->addr
= ptr
;
128 bss_tracker
->len
= sh
->size
;
134 /* Perform relocations of given section */
135 static int relocate(struct elfheader
*eh
, struct sheader
*sh
, long shrel_idx
, ULONG_PTR virt
)
137 struct sheader
*shrel
= &sh
[shrel_idx
];
138 struct sheader
*shsymtab
= &sh
[shrel
->link
];
139 struct sheader
*toreloc
= &sh
[shrel
->info
];
141 struct symbol
*symtab
= (struct symbol
*)((unsigned long)shsymtab
->addr
);
142 struct relo
*rel
= (struct relo
*)((unsigned long)shrel
->addr
);
143 char *section
= (char *)((unsigned long)toreloc
->addr
);
145 unsigned int numrel
= (unsigned long)shrel
->size
/ (unsigned long)shrel
->entsize
;
148 struct symbol
*SysBase_sym
= NULL
;
150 DREL(kprintf("[ELF Loader] performing %d relocations, virtual address %p\n", numrel
, virt
));
152 for (i
=0; i
<numrel
; i
++, rel
++)
154 struct symbol
*sym
= &symtab
[ELF32_R_SYM(rel
->info
)];
155 unsigned long *p
= (unsigned long *)§ion
[rel
->offset
];
157 const char * name
= (char *)((unsigned long)sh
[shsymtab
->link
].addr
) + sym
->name
;
158 switch (sym
->shindex
)
161 DREL(kprintf("[ELF Loader] Undefined symbol '%s' while relocating the section '%s'\n",
162 (char *)((unsigned long)sh
[shsymtab
->link
].addr
) + sym
->name
,
163 (char *)((unsigned long)sh
[eh
->shstrndx
].addr
) + toreloc
->name
));
167 DREL(kprintf("[ELF Loader] COMMON symbol '%s' while relocating the section '%s'\n",
168 (char *)((unsigned long)sh
[shsymtab
->link
].addr
) + sym
->name
,
169 (char *)((unsigned long)sh
[eh
->shstrndx
].addr
) + toreloc
->name
));
174 if (SysBase_sym
== NULL
) {
175 if (strncmp(name
, "SysBase", 8) == 0) {
176 DREL(kprintf("[ELF Loader] got SysBase\n"));
181 } else if (SysBase_sym
== sym
) {
182 SysBase_yes
: s
= (ULONG_PTR
)SysBaseAddr
;
184 SysBase_no
: s
= sym
->value
;
188 s
= (unsigned long)sh
[sym
->shindex
].addr
+ sym
->value
;
193 DREL(printf("[ELF Loader] Relocating symbol "));
194 DREL(if (sym
->name
) printf("%s", name
); else printf("<unknown>"));
195 DREL(printf("type "));
196 switch (ELF32_R_TYPE(rel
->info
))
198 case R_386_32
: /* 32bit absolute */
199 DREL(printf("R_386_32"));
207 case R_386_PC32
: /* 32bit PC relative */
208 DREL(printf("R_386_PC32"));
209 *p
+= (s
- (ULONG_PTR
)p
);
213 DREL(printf("R_386_NONE"));
217 printf("[ELF Loader] Unrecognized relocation type %d %d\n", i
, (unsigned int)ELF32_R_TYPE(rel
->info
));
220 DREL(printf(" -> 0x%p\n", *p
));
225 int load_elf_file(void *file
, ULONG_PTR virt
)
232 D(kprintf("[ELF Loader] Loading ELF module from virtual address %p\n", virt
));
234 /* Check the header of ELF file */
235 if (!read_block(file
, 0, &eh
, sizeof(eh
)) ||
236 !check_header(&eh
) ||
237 !(sh
= load_block(file
, eh
.shoff
, eh
.shnum
* eh
.shentsize
))) {
238 kprintf("[ELF Loader] Wrong module header, aborting.\n");
242 for(i
= 0; i
< eh
.shnum
; i
++) {
243 if (sh
[i
].flags
& SHF_ALLOC
)
244 ksize
+= (sh
[i
].size
+ sh
[i
].addralign
- 1);
247 kbase
= malloc(ksize
);
250 printf("[ELF Loader] Failed to allocate %lu bytes for kernel\n", ksize
);
253 D(printf("[ELF Loader] Kernel memory allocated: %p-%p (%lu bytes)\n", kbase
, kbase
+ ksize
, ksize
));
255 /* Iterate over the section header in order to prepare memory and eventually load some hunks */
256 for (i
=0; i
< eh
.shnum
; i
++)
258 /* Load the symbol and string tables */
259 if (sh
[i
].type
== SHT_SYMTAB
|| sh
[i
].type
== SHT_STRTAB
)
261 D(printf("[ELF Loader] Symbol table\n"));
262 sh
[i
].addr
= load_block(file
, sh
[i
].offset
, sh
[i
].size
);
264 /* Does the section require memoy allcation? */
265 else if (sh
[i
].flags
& SHF_ALLOC
)
267 D(printf("[ELF Loader] Allocated section\n"));
268 /* Yup, it does. Load the hunk */
269 if (!load_hunk(file
, &sh
[i
]))
271 kprintf("[ELF Loader] Error at loading of the hunk!\n");
273 D(else printf("[ELF Loader] shared mem@0x%x\n", sh
[i
].addr
));
277 /* For every loaded section perform the relocations */
278 for (i
=0; i
< eh
.shnum
; i
++)
280 if ((sh
[i
].type
== SHT_RELA
|| sh
[i
].type
== SHT_REL
) && sh
[sh
[i
].info
].addr
)
282 sh
[i
].addr
= load_block(file
, sh
[i
].offset
, sh
[i
].size
);
283 if (!sh
[i
].addr
|| !relocate(&eh
, sh
, i
, virt
))
285 kprintf("[ELF Loader] Relocation error!\n");
287 free_block(sh
[i
].addr
);
289 else if (sh
[i
].type
== SHT_SYMTAB
|| sh
[i
].type
== SHT_STRTAB
)
290 free_block(sh
[i
].addr
);