Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / arch / all-mingw32 / bootstrap / elfloader32.c
blobada8feb66a5b59f6d35e7e21662d3f6e7fcb3d5b
1 /*
2 Copyright (C) 2006-2009 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 <windows.h>
10 #include "elfloader32.h"
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <strings.h>
15 #define D(X)
16 #define DREL(x)
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.
24 char *kbase;
25 char *ptr_ro;
26 void ** SysBaseAddr;
28 struct _bss_tracker {
29 void *addr;
30 size_t len;
31 } *bss_tracker;
33 void *kernel_lowest()
35 return kbase;
38 void *kernel_highest()
40 return ptr_ro - 1;
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);
57 return 1;
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);
68 return dest;
71 static void free_block(void * block)
73 free(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' ||
87 eh->ident[3] != 'F'
90 D(kprintf("[ELF Loader] Not an ELF object\n"));
91 return 0;
94 if (eh->type != ET_REL || eh->machine != EM_386)
96 D(kprintf("[ELF Loader] Wrong object type or wrong architecture\n"));
97 return 0;
99 return 1;
103 * Get the memory for chunk and load it
105 static int load_hunk(void *file, struct sheader *sh)
107 void *ptr=(void*)0;
109 /* empty chunk? Who cares :) */
110 if (!sh->size)
111 return 1;
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));
115 ptr = ptr_ro;
116 ptr_ro = ptr_ro + sh->size;
117 D(kprintf("%p\n", (unsigned int)ptr));
119 sh->addr = 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);
124 else
126 memset(ptr, 0, sh->size);
127 bss_tracker->addr = ptr;
128 bss_tracker->len = sh->size;
129 bss_tracker++;
131 return 1;
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;
146 unsigned int i;
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 *)&section[rel->offset];
156 ULONG_PTR s;
157 const char * name = (char *)((unsigned long)sh[shsymtab->link].addr) + sym->name;
158 switch (sym->shindex)
160 case SHN_UNDEF:
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));
164 return 0;
166 case SHN_COMMON:
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));
171 return 0;
173 case SHN_ABS:
174 if (SysBase_sym == NULL) {
175 if (strncmp(name, "SysBase", 8) == 0) {
176 DREL(kprintf("[ELF Loader] got SysBase\n"));
177 SysBase_sym = sym;
178 goto SysBase_yes;
179 } else
180 goto SysBase_no;
181 } else if (SysBase_sym == sym) {
182 SysBase_yes: s = (ULONG_PTR)SysBaseAddr;
183 } else
184 SysBase_no: s = sym->value;
185 break;
187 default:
188 s = (unsigned long)sh[sym->shindex].addr + sym->value;
191 s += virt;
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"));
200 *p += s;
201 if (*p < kbase) {
202 exit(0);
205 break;
207 case R_386_PC32: /* 32bit PC relative */
208 DREL(printf("R_386_PC32"));
209 *p += (s - (ULONG_PTR)p);
210 break;
212 case R_386_NONE:
213 DREL(printf("R_386_NONE"));
214 break;
216 default:
217 printf("[ELF Loader] Unrecognized relocation type %d %d\n", i, (unsigned int)ELF32_R_TYPE(rel->info));
218 return 0;
220 DREL(printf(" -> 0x%p\n", *p));
222 return 1;
225 int load_elf_file(void *file, ULONG_PTR virt)
227 struct elfheader eh;
228 struct sheader *sh;
229 unsigned long i;
230 size_t ksize = 0;
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");
239 return;
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);
248 ptr_ro = kbase;
249 if (!kbase) {
250 printf("[ELF Loader] Failed to allocate %lu bytes for kernel\n", ksize);
251 return 0;
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);
292 free_block(sh);
293 return 1;