Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / arch / i386-darwin / bootstrap / elfloader32.c
blobebb37d6302a8a164df36ee35f5a4b9e37f35e832
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 #define DEBUG
10 #define NATIVE
12 #include "../include/aros/kernel.h"
13 #include "elfloader32.h"
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <strings.h>
17 //#include "screen.h"
18 //#include "bootstrap.h"
19 //#include "support.h"
21 #ifdef DEBUG
22 #define D
23 #else
24 #define D(X)
25 #endif
26 #define kprintf printf
29 * This two pointers are used by the ELF loader to claim for memory ranges for both
30 * the RW sections (.data, .bss and such) and RO sections (.text, .rodata....) of executable.
31 * Keeping both areas of memory separate reduces the memory waste when more modules are
32 * loaded. Moreover, the whole RO range may be marked for MMU as read-only at once.
34 char *ptr_ro = 0;
35 char *ptr_rw = 0;
36 void ** SysBaseAddr;
38 struct _bss_tracker {
39 unsigned long long addr;
40 unsigned long long len;
41 } *bss_tracker;
43 void *kernel_lowest()
45 return ptr_rw;
48 void *kernel_highest()
50 return ptr_ro;
53 void set_base_address(void *ptr, void *tracker, void ** sysbaseaddr)
55 printf("[ELF Loader] set_base_address %p %p %p\n",ptr,tracker,sysbaseaddr);
56 ptr_ro = ptr_rw = ptr;
57 bss_tracker = (struct _bss_tracker *)tracker;
58 SysBaseAddr = sysbaseaddr;
62 * read_block interface. we want to read from files here
64 static int read_block(void *file, long offset, void *dest, long length)
66 fseek(file, offset, SEEK_SET);
67 fread(dest,(size_t)length, 1, file);
68 return 1;
72 * load_block also allocates teh memory
74 static void *load_block(void *file, long offset, long length)
76 void * dest = malloc(length);
77 fseek(file, offset, SEEK_SET);
78 fread(dest, (size_t)length, 1, file);
79 return dest;
82 static void free_block(void * block)
84 free(block);
89 * Test for correct ELF header here
91 static int check_header(struct elfheader *eh)
95 eh->ident[0] != 0x7f ||
96 eh->ident[1] != 'E' ||
97 eh->ident[2] != 'L' ||
98 eh->ident[3] != 'F'
101 D(kprintf("[ELF Loader] Not an ELF object\n"));
102 return 0;
105 if (eh->type != ET_REL || eh->machine != EM_386)
107 D(kprintf("[ELF Loader] Wrong object type or wrong architecture\n"));
108 return 0;
110 return 1;
114 * Get the memory for chunk and load it
116 static int load_hunk(void *file, struct sheader *sh)
118 void *ptr=(void*)0;
120 /* empty chunk? Who cares :) */
121 if (!sh->size)
122 return 1;
126 /* Allocate a chunk with write access - take aligned memory beneath the RO kernel */
127 if (sh->flags & SHF_WRITE)
129 D(kprintf("[ELF Loader] RW chunk (%d bytes, align=%d) @ ", (unsigned int)sh->size, (unsigned int)sh->addralign));
130 #if 1
131 ptr = (void*)(((unsigned long)ptr_rw - (unsigned long)sh->size - (unsigned long)sh->addralign + 1) & ~((unsigned long)sh->addralign-1));
132 ptr_rw = ptr;
133 #else
134 ptr = malloc(sh->size + sh->addralign);
135 #endif
137 else
139 /* Read-Only mode? Get the memory from the kernel space, align it accorting to the demand */
140 #if 1
141 D(kprintf("[ELF Loader] RO chunk (%d bytes, align=%d) @ ", (unsigned int)sh->size, (unsigned int)sh->addralign));
142 ptr_ro = (char *)(((unsigned long)ptr_ro + (unsigned long)sh->addralign - 1) & ~((unsigned long)sh->addralign-1));
143 ptr = ptr_ro;
144 ptr_ro = ptr_ro + sh->size;
145 #else
146 ptr = malloc(sh->size + sh->addralign);
147 #endif
149 D(kprintf("%p\n", (unsigned int)ptr));
151 sh->addr = ptr;
153 /* copy block of memory from ELF file if it exists */
154 if (sh->type != SHT_NOBITS)
155 return read_block(file, sh->offset, (void *)((unsigned long)sh->addr), sh->size);
156 else
158 bzero(ptr, sh->size);
159 bss_tracker->addr = (unsigned long)ptr;
160 bss_tracker->len = sh->size;
161 bss_tracker++;
164 return 1;
167 /* Perform relocations of given section */
168 static int relocate(struct elfheader *eh, struct sheader *sh, long shrel_idx, unsigned long long virt)
170 struct sheader *shrel = &sh[shrel_idx];
171 struct sheader *shsymtab = &sh[shrel->link];
172 struct sheader *toreloc = &sh[shrel->info];
174 struct symbol *symtab = (struct symbol *)((unsigned long)shsymtab->addr);
175 struct relo *rel = (struct relo *)((unsigned long)shrel->addr);
176 char *section = (char *)((unsigned long)toreloc->addr);
178 unsigned int numrel = (unsigned long)shrel->size / (unsigned long)shrel->entsize;
179 unsigned int i;
181 struct symbol *SysBase_sym = (void*)0;
183 D(kprintf("[ELF Loader] performing %d relocations, target address %p%p\n",
184 numrel, (unsigned long)(virt >> 32), (unsigned long)virt));
186 for (i=0; i<numrel; i++, rel++)
188 struct symbol *sym = &symtab[ELF32_R_SYM(rel->info)];
189 unsigned long *p = (unsigned long *)&section[rel->offset];
190 unsigned long long s;
191 const char * name = (char *)((unsigned long)sh[shsymtab->link].addr) + sym->name;
192 switch (sym->shindex)
194 case SHN_UNDEF:
195 D(kprintf("[ELF Loader] Undefined symbol '%s' while relocating the section '%s'\n",
196 (char *)((unsigned long)sh[shsymtab->link].addr) + sym->name,
197 (char *)((unsigned long)sh[eh->shstrndx].addr) + toreloc->name));
198 return 0;
200 case SHN_COMMON:
201 D(kprintf("[ELF Loader] COMMON symbol '%s' while relocating the section '%s'\n",
202 (char *)((unsigned long)sh[shsymtab->link].addr) + sym->name,
203 (char *)((unsigned long)sh[eh->shstrndx].addr) + toreloc->name));
205 return 0;
207 case SHN_ABS:
208 if (SysBase_sym == (void*)0)
210 if (strncmp(name, "SysBase", 8) == 0)
212 D(kprintf("[ELF Loader] got SysBase\n"));
213 SysBase_sym = sym;
214 goto SysBase_yes;
216 else
217 goto SysBase_no;
219 else
220 if (SysBase_sym == sym)
222 SysBase_yes: s = SysBaseAddr;
224 else
225 SysBase_no: s = sym->value;
226 break;
228 default:
229 s = (unsigned long)sh[sym->shindex].addr + virt + sym->value;
232 s+=virt;
234 switch (ELF32_R_TYPE(rel->info))
236 case R_386_32: /* 32bit absolute */
237 *p += s;
238 break;
240 case R_386_PC32: /* 32bit PC relative */
241 *p += s - (unsigned int)p;
242 break;
244 case R_386_NONE:
245 break;
247 default:
248 kprintf("[ELF Loader] Unrecognized relocation type %d %d\n", i, (unsigned int)ELF32_R_TYPE(rel->info));
249 return 0;
251 if (sym->name)
252 D(kprintf("[ELF Loader] relocated symbol: %s->0x%x\n",name,*p));
254 return 1;
257 void load_elf_file(void *file, unsigned long long virt)
259 struct elfheader eh;
260 struct sheader *sh;
261 long i;
262 int addr_displayed = 0;
264 D(kprintf("[ELF Loader] Loading ELF module from address %p\n", (unsigned int)file));
266 /* Check the header of ELF file */
269 !read_block(file, 0, &eh, sizeof(eh)) ||
270 !check_header(&eh) ||
271 !(sh = load_block(file, eh.shoff, eh.shnum * eh.shentsize))
274 kprintf("[ELF Loader] Wrong module header, aborting.\n");
275 return;
278 /* Iterate over the section header in order to prepare memory and eventually load some hunks */
279 for (i=0; i < eh.shnum; i++)
281 /* Load the symbol and string tables */
282 if (sh[i].type == SHT_SYMTAB || sh[i].type == SHT_STRTAB)
284 sh[i].addr = load_block(file, sh[i].offset, sh[i].size);
286 /* Does the section require memoy allcation? */
287 else if (sh[i].flags & SHF_ALLOC)
289 /* Yup, it does. Load the hunk */
290 if (!load_hunk(file, &sh[i]))
292 kprintf("[ELF Loader] Error at loading of the hunk!\n");
294 else if (!addr_displayed)
296 kprintf("[ELF Loader] shared mem@0x%x\n", sh[i].addr);
297 addr_displayed = 1;
302 /* For every loaded section perform the relocations */
303 for (i=0; i < eh.shnum; i++)
305 if ((sh[i].type == SHT_RELA || sh[i].type == SHT_REL) && sh[sh[i].info].addr)
307 sh[i].addr = load_block(file, sh[i].offset, sh[i].size);
308 if (!sh[i].addr || !relocate(&eh, sh, i, virt))
310 kprintf("[ELF Loader] Relocation error!\n");
312 free_block(sh[i].addr);
314 else if (sh[i].type == SHT_SYMTAB || sh[i].type == SHT_STRTAB)
315 free_block(sh[i].addr);
317 free_block(sh);