Use more appropriate types for pt_regs struct, e.g. 16-bit types for 16-bit
[cake.git] / rom / dos / internalloadseg_elf_aros.c
blobe69857a1846d46ec115231571ffcb1154ac48a94
1 /*
2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Code to dynamically load ELF executables
6 Lang: english
8 1997/12/13: Changed filename to internalloadseg_elf.c
9 Original file was created by digulla.
11 #include <exec/memory.h>
12 #include <proto/exec.h>
13 #include <dos/dosasl.h>
14 #include <proto/dos.h>
15 #include <proto/arossupport.h>
16 #include <aros/asmcall.h>
17 #include "dos_intern.h"
18 #include "internalloadseg.h"
19 #define DEBUG 0
20 #include <aros/debug.h>
21 #include <string.h>
22 #include <stddef.h>
24 #define SHT_PROGBITS 1
25 #define SHT_SYMTAB 2
26 #define SHT_STRTAB 3
27 #define SHT_RELA 4
28 #define SHT_NOBITS 8
29 #define SHT_REL 9
31 #define SHT_LOOS 0x60000000
32 #define SHT_AROS_REL32 (SHT_LOOS)
34 #define ET_REL 1
35 #define ET_EXEC 2
37 #define EM_386 3
38 #define EM_68K 4
39 #define EM_PPC 20
40 #define EM_ARM 40
41 #define EM_X86_64 62
43 #define R_386_NONE 0
44 #define R_386_32 1
45 #define R_386_PC32 2
47 #define R_X86_64_NONE 0
48 #define R_X86_64_64 1
49 #define R_X86_64_PC32 2
51 #define R_68k_NONE 0
52 #define R_68K_32 1
53 #define R_68K_PC32 4
55 #define STT_OBJECT 1
56 #define STT_FUNC 2
58 #define SHN_ABS 0xfff1
59 #define SHN_COMMON 0xfff2
60 #define SHN_UNDEF 0
62 #define SHF_ALLOC (1 << 1)
64 #define ELF32_ST_TYPE(i) ((i) & 0x0F)
66 #define EI_VERSION 6
67 #define EV_CURRENT 1
69 #define EI_DATA 5
70 #define ELFDATA2LSB 1
71 #define ELFDATA2MSB 2
73 #define EI_CLASS 4
74 #define ELFCLASS32 1
75 #define ELFCLASS64 2
77 #define EI_OSABI 7
78 #define EI_ABIVERSION 8
80 #define ELFOSABI_AROS 15
82 #define PF_X (1 << 0)
85 #define ELF32_R_SYM(val) ((val) >> 8)
86 #define ELF32_R_TYPE(val) ((val) & 0xff)
87 #define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff))
90 struct elfheader
92 UBYTE ident[16];
93 UWORD type;
94 UWORD machine;
95 ULONG version;
96 APTR entry;
97 ULONG phoff;
98 ULONG shoff;
99 ULONG flags;
100 UWORD ehsize;
101 UWORD phentsize;
102 UWORD phnum;
103 UWORD shentsize;
104 UWORD shnum;
105 UWORD shstrndx;
108 struct sheader
110 ULONG name;
111 ULONG type;
112 ULONG flags;
113 APTR addr;
114 ULONG offset;
115 ULONG size;
116 ULONG link;
117 ULONG info;
118 ULONG addralign;
119 ULONG entsize;
122 struct pheader
124 ULONG type;
125 ULONG offset;
126 APTR vaddr;
127 APTR paddr;
128 ULONG filesz;
129 ULONG memsz;
130 ULONG flags;
131 ULONG align;
134 #define PT_LOAD 1
136 struct hunk
138 ULONG size;
139 BPTR next;
140 char data[0];
141 } __attribute__((packed));
143 #define BPTR2HUNK(bptr) ((struct hunk *)((char *)BADDR(bptr) - offsetof(struct hunk, next)))
144 #define HUNK2BPTR(hunk) MKBADDR(&hunk->next)
146 #undef MyRead
147 #undef MyAlloc
148 #undef MyFree
151 #define MyRead(file, buf, size) \
152 AROS_CALL3 \
154 LONG, funcarray[0], \
155 AROS_LCA(BPTR, file, D1), \
156 AROS_LCA(void *, buf, D2), \
157 AROS_LCA(LONG, size, D3), \
158 struct DosLibrary *, DOSBase \
162 #define MyAlloc(size, flags) \
163 AROS_CALL2 \
165 void *, funcarray[1], \
166 AROS_LCA(ULONG, size, D0), \
167 AROS_LCA(ULONG, flags, D1), \
168 struct ExecBase *, SysBase \
172 #define MyFree(addr, size) \
173 AROS_CALL2NR \
175 void, funcarray[2], \
176 AROS_LCA(void *, addr, A1), \
177 AROS_LCA(ULONG, size, D0), \
178 struct ExecBase *, SysBase \
181 static int read_block
183 BPTR file,
184 ULONG offset,
185 APTR buffer,
186 ULONG size,
187 SIPTR *funcarray,
188 struct DosLibrary *DOSBase
191 UBYTE *buf = (UBYTE *)buffer;
192 LONG subsize;
194 if (Seek(file, offset, OFFSET_BEGINNING) < 0)
195 return 0;
197 while (size)
199 subsize = MyRead(file, buf, size);
201 if (subsize <= 0)
203 if (subsize == 0)
205 D(bug("[ELF Loader] Error while reading from file.\n"));
206 D(bug("[ELF Loader] Offset = %ld - Size = %ld\n", offset, size));
207 SetIoErr(ERROR_BAD_HUNK);
210 return 0;
213 buf += subsize;
214 size -= subsize;
217 return 1;
220 static void * load_block
222 BPTR file,
223 ULONG offset,
224 ULONG size,
225 SIPTR *funcarray,
226 struct DosLibrary *DOSBase
229 void *block = MyAlloc(size, MEMF_ANY);
230 if (block)
232 if (read_block(file, offset, block, size, funcarray, DOSBase))
233 return block;
235 MyFree(block, size);
237 else
238 SetIoErr(ERROR_NO_FREE_STORE);
240 return NULL;
243 static int check_header(struct elfheader *eh, struct DosLibrary *DOSBase)
247 eh->ident[0] != 0x7f ||
248 eh->ident[1] != 'E' ||
249 eh->ident[2] != 'L' ||
250 eh->ident[3] != 'F'
253 D(bug("[ELF Loader] Not an elf object\n"));
254 SetIoErr(ERROR_NOT_EXECUTABLE);
255 return 0;
260 eh->ident[EI_CLASS] != (ELFCLASS32 || ELFCLASS64) ||
261 eh->ident[EI_VERSION] != EV_CURRENT ||
262 eh->ident[EI_OSABI] != ELFOSABI_AROS ||
263 eh->ident[EI_ABIVERSION] != 0 ||
264 eh->type != ET_EXEC ||
266 #if defined(__i386__)
268 eh->ident[EI_DATA] != ELFDATA2LSB ||
269 eh->machine != EM_386
271 #elif defined(__x86_64__)
273 eh->ident[EI_DATA] != ELFDATA2LSB ||
274 eh->machine != EM_X86_64
276 #elif defined(__mc68000__)
278 eh->ident[EI_DATA] != ELFDATA2MSB ||
279 eh->machine != EM_68K
281 #elif defined(__ppc__) || defined(__powerpc__)
282 eh->ident[EI_DATA] != ELFDATA2MSB ||
283 eh->machine != EM_PPC
285 #elif defined(__arm__)
287 eh->ident[EI_DATA] != ELFDATA2LSB ||
288 eh->machine != EM_ARM
290 #else
291 # error Your architecture is not supported
292 #endif
295 D(bug("[ELF Loader] Object is of wrong type\n"));
296 D(bug("[ELF Loader] EI_CLASS is %d - should be %d\n", eh->ident[EI_CLASS], ELFCLASS32));
297 D(bug("[ELF Loader] EI_VERSION is %d - should be %d\n", eh->ident[EI_VERSION], EV_CURRENT));
298 D(bug("[ELF Loader] type is %d - should be %d\n", eh->type, ET_REL));
300 #if defined (__i386__)
301 D(bug("[ELF Loader] EI_DATA is %d - should be %d\n", eh->ident[EI_DATA], ELFDATA2LSB));
302 #elif defined(__mc68000__)
303 D(bug("[ELF Loader] EI_DATA is %d - should be %d\n", eh->ident[EI_DATA], ELFDATA2MSB));
304 #elif defined(__ppc__) || defined(__powerpc__)
305 D(bug("[ELF Loader] EI_DATA is %d - should be %d\n", eh->ident[EI_DATA],ELFDATA2MSB));
306 #elif defined(__arm__)
307 D(bug("[ELF Loader] EI_DATA is %d - should be %d\n", eh->ident[EI_DATA], ELFDATA2MSB));
308 #endif
310 #if defined (__i386__)
311 D(bug("[ELF Loader] machine is %d - should be %d\n", eh->machine, EM_386));
312 #elif defined(__mc68000__)
313 D(bug("[ELF Loader] machine is %d - should be %d\n", eh->machine, EM_68K));
314 #elif defined(__ppc__) || defined(__powerpc__)
315 D(bug("[ELF Loader] machine is %d - should be %d\n", eh->machine, EM_PPC));
316 #elif defined(__arm__)
317 D(bug("[ELF Loader] machine is %d - should be %d\n", eh->machine, EM_ARM));
318 #endif
320 SetIoErr(ERROR_OBJECT_WRONG_TYPE);
321 return 0;
324 return 1;
327 static int load_hunk
329 BPTR file,
330 BPTR **next_hunk_ptr,
331 struct pheader *ph,
332 SIPTR *funcarray,
333 struct DosLibrary *DOSBase
336 struct hunk *hunk;
338 /* Sanity check */
339 if (ph->memsz < ph->filesz)
341 SetIoErr(ERROR_BAD_HUNK);
342 return 0;
345 if (!ph->memsz)
346 return 1;
348 hunk = MyAlloc(ph->memsz + sizeof(struct hunk), MEMF_ANY);
349 if (hunk)
351 hunk->size = ph->memsz + sizeof(struct hunk);
353 ph->paddr = hunk->data;
355 /* Link the new hunk with the old next one. This makes it possible
356 to handle insertion */
357 hunk->next = BPTR2HUNK(*next_hunk_ptr)->next;
359 /* Link the previous one with the new one */
360 BPTR2HUNK(*next_hunk_ptr)->next = HUNK2BPTR(hunk);
362 /* Update the pointer to the previous one, which is now the current one */
363 *next_hunk_ptr = HUNK2BPTR(hunk);
365 /* Clear out the memory that is not filled with file contents */
366 memset(hunk->data + ph->filesz, 0, ph->memsz - ph->filesz);
368 /* Finally read the segment from the file into memory */
369 return read_block(file, ph->offset, hunk->data, ph->filesz, funcarray, DOSBase);
372 SetIoErr(ERROR_NO_FREE_STORE);
374 return 0;
377 union aros_rel_entry
379 ULONG segment;
380 ULONG offset;
381 ULONG num_entries;
384 static int relocate
386 struct pheader *ph,
387 union aros_rel_entry *rel,
388 ULONG toreloc_idx
391 const char *contents = ph[toreloc_idx].paddr;
393 int num_segments = (rel++)->num_entries;
395 while (num_segments--)
397 const struct pheader *fromreloc = &ph[(rel++)->segment];
398 const ULONG addr_to_add = fromreloc->paddr - fromreloc->vaddr;
399 ULONG num_relocs = (rel++)->num_entries;
401 while (num_relocs--)
402 *((ULONG *)&contents[rel++->offset]) += addr_to_add;
405 return 1;
408 BPTR InternalLoadSeg_ELF_AROS
410 BPTR file,
411 BPTR table __unused,
412 SIPTR *funcarray,
413 SIPTR *stack __unused,
414 struct MinList *seginfos,
415 struct DosLibrary *DOSBase
418 struct elfheader eh;
419 struct sheader *sh = NULL;
420 struct pheader *ph = NULL;
422 BPTR hunks = 0;
423 BPTR *next_hunk_ptr = &hunks;
424 ULONG i;
425 BOOL exec_segment_found = FALSE;
427 /* Load Elf Header and Section Headers */
430 !read_block(file, 0, &eh, sizeof(eh), funcarray, DOSBase) ||
431 !check_header(&eh, DOSBase) ||
432 !(sh = load_block(file, eh.shoff, eh.shnum * eh.shentsize, funcarray, DOSBase)) ||
433 !(ph = load_block(file, eh.phoff, eh.phnum * eh.phentsize, funcarray, DOSBase))
436 goto end;
439 /* Iterate over the program headers in order to do some stuff... */
440 for (i = 0; i < eh.phnum; i++)
442 /* Load the segment in memory if needed, and make a hunk out of it */
443 if (ph[i].type == PT_LOAD)
445 if (!load_hunk(file, &next_hunk_ptr, &ph[i], funcarray, DOSBase))
446 goto error;
448 /* If this segment holds executable code, build a trampoline hunk
449 which points to the entry location into the object */
450 if (ph[i].flags & PF_X)
452 BPTR *next_hunk_ptr2 = &hunks;
453 struct pheader ph_trampoline;
455 if (!exec_segment_found)
456 exec_segment_found = TRUE;
457 else
459 /* We allow only one executable segment per object */
460 SetIoErr(ERROR_BAD_HUNK);
461 goto error;
466 !((eh.entry >= ph[i].vaddr) &&
467 (eh.entry <= (ph[i].vaddr + ph[i].memsz)))
470 /* The entry point must fall into the range of the executable
471 segment */
472 SetIoErr(ERROR_BAD_HUNK);
473 goto error;
476 /* Build a fake program header */
477 ph_trampoline.filesz = 0;
478 ph_trampoline.memsz = sizeof (struct FullJumpVec);
480 /* Now allocate the hunk relative to the fake ph */
481 if (!load_hunk(file, &next_hunk_ptr2, &ph_trampoline, funcarray, DOSBase))
482 goto error;
484 /* Finally, build the trampoline */
485 __AROS_SET_FULLJMP
487 ph_trampoline.paddr,
488 (ULONG)eh.entry + (ULONG)ph[i].paddr - (ULONG)ph[i].vaddr
494 /* Relocate the segments */
495 for (i = 0; i < eh.shnum; i++)
497 if (sh[i].type == SHT_AROS_REL32)
499 sh[i].addr = load_block(file, sh[i].offset, sh[i].size, funcarray, DOSBase);
500 if (!sh[i].addr || !relocate(ph, sh[i].addr, sh[i].info))
501 goto error;
503 MyFree(sh[i].addr, sh[i].size);
504 sh[i].addr = NULL;
508 /* No errors */
510 goto end;
512 error:
514 /* There were some errors, deallocate the hunks */
516 InternalUnLoadSeg(hunks, (VOID_FUNC)funcarray[2]);
517 hunks = 0;
519 end:
521 /* Free the section headers */
522 if (sh)
523 MyFree(sh, eh.shnum * eh.shentsize);
525 /* Free the program header */
526 if (ph)
527 MyFree(ph, eh.phnum * eh.phentsize);
529 return hunks;
532 #undef MyRead
533 #undef MyAlloc
534 #undef MyFree