Re-enabled use of AROS.Boot file due to lack of general enthusiasm for
[tangerine.git] / arch / all-mingw32 / bootstrap / elfloader32.c
blob358cbeae03d450b902719d5b54f7f9416b1d9be3
1 /*
2 Copyright (C) 2006 The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: ELF32 loader extracted from our internal_load_seg_elf in dos.library.
6 Lang: English
7 */
9 #include "elfloader32.h"
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <strings.h>
14 #define D(X)
16 #define kprintf printf
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 = 0;
25 char *ptr_rw = 0;
26 void ** SysBaseAddr;
28 struct _bss_tracker {
29 void *addr;
30 size_t len;
31 } *bss_tracker;
33 void *kernel_lowest()
35 return ptr_rw;
38 void *kernel_highest()
40 return ptr_ro;
43 void set_base_address(void *ptr, void *tracker, void ** sysbaseaddr)
45 printf("[ELF Loader] set_base_address %p %p %p\n",ptr,tracker,sysbaseaddr);
46 ptr_ro = ptr_rw = ptr;
47 bss_tracker = (struct _bss_tracker *)tracker;
48 SysBaseAddr = sysbaseaddr;
52 * read_block interface. we want to read from files here
54 static int read_block(void *file, long offset, void *dest, long length)
56 fseek(file, offset, SEEK_SET);
57 fread(dest,(size_t)length, 1, file);
58 return 1;
62 * load_block also allocates teh memory
64 static void *load_block(void *file, long offset, long length)
66 void * dest = malloc(length);
67 fseek(file, offset, SEEK_SET);
68 fread(dest, (size_t)length, 1, file);
69 return dest;
72 static void free_block(void * block)
74 free(block);
79 * Test for correct ELF header here
81 static int check_header(struct elfheader *eh)
85 eh->ident[0] != 0x7f ||
86 eh->ident[1] != 'E' ||
87 eh->ident[2] != 'L' ||
88 eh->ident[3] != 'F'
91 D(kprintf("[ELF Loader] Not an ELF object\n"));
92 return 0;
95 if (eh->type != ET_REL || eh->machine != EM_386)
97 D(kprintf("[ELF Loader] Wrong object type or wrong architecture\n"));
98 return 0;
100 return 1;
104 * Get the memory for chunk and load it
106 static int load_hunk(void *file, struct sheader *sh)
108 void *ptr=(void*)0;
110 /* empty chunk? Who cares :) */
111 if (!sh->size)
112 return 1;
116 /* Allocate a chunk with write access - take aligned memory beneath the RO kernel */
117 if (sh->flags & SHF_WRITE)
119 D(kprintf("[ELF Loader] RW chunk (%d bytes, align=%d) @ ", (unsigned int)sh->size, (unsigned int)sh->addralign));
120 #if 1
121 ptr = (void*)(((unsigned long)ptr_rw - (unsigned long)sh->size - (unsigned long)sh->addralign + 1) & ~((unsigned long)sh->addralign-1));
122 ptr_rw = ptr;
123 #else
124 ptr = malloc(sh->size + sh->addralign);
125 #endif
127 else
129 /* Read-Only mode? Get the memory from the kernel space, align it accorting to the demand */
130 #if 1
131 D(kprintf("[ELF Loader] RO chunk (%d bytes, align=%d) @ ", (unsigned int)sh->size, (unsigned int)sh->addralign));
132 ptr_ro = (char *)(((unsigned long)ptr_ro + (unsigned long)sh->addralign - 1) & ~((unsigned long)sh->addralign-1));
133 ptr = ptr_ro;
134 ptr_ro = ptr_ro + sh->size;
135 #else
136 ptr = malloc(sh->size + sh->addralign);
137 #endif
139 D(kprintf("%p\n", (unsigned int)ptr));
141 sh->addr = ptr;
143 /* copy block of memory from ELF file if it exists */
144 if (sh->type != SHT_NOBITS)
145 return read_block(file, sh->offset, (void *)((unsigned long)sh->addr), sh->size);
146 else
148 memset(ptr, 0, sh->size);
149 bss_tracker->addr = ptr;
150 bss_tracker->len = sh->size;
151 bss_tracker++;
154 return 1;
157 /* Perform relocations of given section */
158 static int relocate(struct elfheader *eh, struct sheader *sh, long shrel_idx, unsigned long long virt)
160 struct sheader *shrel = &sh[shrel_idx];
161 struct sheader *shsymtab = &sh[shrel->link];
162 struct sheader *toreloc = &sh[shrel->info];
164 struct symbol *symtab = (struct symbol *)((unsigned long)shsymtab->addr);
165 struct relo *rel = (struct relo *)((unsigned long)shrel->addr);
166 char *section = (char *)((unsigned long)toreloc->addr);
168 unsigned int numrel = (unsigned long)shrel->size / (unsigned long)shrel->entsize;
169 unsigned int i;
171 struct symbol *SysBase_sym = (void*)0;
173 D(kprintf("[ELF Loader] performing %d relocations, target address %p%p\n",
174 numrel, (unsigned long)(virt >> 32), (unsigned long)virt));
176 for (i=0; i<numrel; i++, rel++)
178 struct symbol *sym = &symtab[ELF32_R_SYM(rel->info)];
179 unsigned long *p = (unsigned long *)&section[rel->offset];
180 unsigned long long s;
181 const char * name = (char *)((unsigned long)sh[shsymtab->link].addr) + sym->name;
182 switch (sym->shindex)
184 case SHN_UNDEF:
185 D(kprintf("[ELF Loader] Undefined symbol '%s' while relocating the section '%s'\n",
186 (char *)((unsigned long)sh[shsymtab->link].addr) + sym->name,
187 (char *)((unsigned long)sh[eh->shstrndx].addr) + toreloc->name));
188 return 0;
190 case SHN_COMMON:
191 D(kprintf("[ELF Loader] COMMON symbol '%s' while relocating the section '%s'\n",
192 (char *)((unsigned long)sh[shsymtab->link].addr) + sym->name,
193 (char *)((unsigned long)sh[eh->shstrndx].addr) + toreloc->name));
195 return 0;
197 case SHN_ABS:
198 if (SysBase_sym == (void*)0)
200 if (strncmp(name, "SysBase", 8) == 0)
202 D(kprintf("[ELF Loader] got SysBase\n"));
203 SysBase_sym = sym;
204 goto SysBase_yes;
206 else
207 goto SysBase_no;
209 else
210 if (SysBase_sym == sym)
212 SysBase_yes: s = SysBaseAddr;
214 else
215 SysBase_no: s = sym->value;
216 break;
218 default:
219 s = (unsigned long)sh[sym->shindex].addr + virt + sym->value;
222 s+=virt;
224 switch (ELF32_R_TYPE(rel->info))
226 case R_386_32: /* 32bit absolute */
227 *p += s;
228 break;
230 case R_386_PC32: /* 32bit PC relative */
231 *p += s - (unsigned int)p;
232 break;
234 case R_386_NONE:
235 break;
237 default:
238 kprintf("[ELF Loader] Unrecognized relocation type %d %d\n", i, (unsigned int)ELF32_R_TYPE(rel->info));
239 return 0;
241 if (sym->name)
242 D(kprintf("[ELF Loader] relocated symbol: %s->0x%x\n",name,*p));
244 return 1;
247 void load_elf_file(void *file, unsigned long long virt)
249 struct elfheader eh;
250 struct sheader *sh;
251 long i;
252 int addr_displayed = 0;
254 D(kprintf("[ELF Loader] Loading ELF module from address %p\n", (unsigned int)file));
256 /* Check the header of ELF file */
259 !read_block(file, 0, &eh, sizeof(eh)) ||
260 !check_header(&eh) ||
261 !(sh = load_block(file, eh.shoff, eh.shnum * eh.shentsize))
264 kprintf("[ELF Loader] Wrong module header, aborting.\n");
265 return;
268 /* Iterate over the section header in order to prepare memory and eventually load some hunks */
269 for (i=0; i < eh.shnum; i++)
271 /* Load the symbol and string tables */
272 if (sh[i].type == SHT_SYMTAB || sh[i].type == SHT_STRTAB)
274 sh[i].addr = load_block(file, sh[i].offset, sh[i].size);
276 /* Does the section require memoy allcation? */
277 else if (sh[i].flags & SHF_ALLOC)
279 /* Yup, it does. Load the hunk */
280 if (!load_hunk(file, &sh[i]))
282 kprintf("[ELF Loader] Error at loading of the hunk!\n");
284 else if (!addr_displayed)
286 kprintf("[ELF Loader] shared mem@0x%x\n", sh[i].addr);
287 addr_displayed = 1;
292 /* For every loaded section perform the relocations */
293 for (i=0; i < eh.shnum; i++)
295 if ((sh[i].type == SHT_RELA || sh[i].type == SHT_REL) && sh[sh[i].info].addr)
297 sh[i].addr = load_block(file, sh[i].offset, sh[i].size);
298 if (!sh[i].addr || !relocate(&eh, sh, i, virt))
300 kprintf("[ELF Loader] Relocation error!\n");
302 free_block(sh[i].addr);
304 else if (sh[i].type == SHT_SYMTAB || sh[i].type == SHT_STRTAB)
305 free_block(sh[i].addr);
307 free_block(sh);