2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
5 Desc: Code to dynamically load ELF executables
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"
20 #include <aros/debug.h>
24 #define SHT_PROGBITS 1
31 #define SHT_LOOS 0x60000000
32 #define SHT_AROS_REL32 (SHT_LOOS)
47 #define R_X86_64_NONE 0
49 #define R_X86_64_PC32 2
58 #define SHN_ABS 0xfff1
59 #define SHN_COMMON 0xfff2
62 #define SHF_ALLOC (1 << 1)
64 #define ELF32_ST_TYPE(i) ((i) & 0x0F)
78 #define EI_ABIVERSION 8
80 #define ELFOSABI_AROS 15
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))
141 } __attribute__((packed
));
143 #define BPTR2HUNK(bptr) ((struct hunk *)((char *)BADDR(bptr) - offsetof(struct hunk, next)))
144 #define HUNK2BPTR(hunk) MKBADDR(&hunk->next)
151 #define MyRead(file, buf, size) \
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) \
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) \
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
188 struct DosLibrary
*DOSBase
191 UBYTE
*buf
= (UBYTE
*)buffer
;
194 if (Seek(file
, offset
, OFFSET_BEGINNING
) < 0)
199 subsize
= MyRead(file
, buf
, size
);
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
);
220 static void * load_block
226 struct DosLibrary
*DOSBase
229 void *block
= MyAlloc(size
, MEMF_ANY
);
232 if (read_block(file
, offset
, block
, size
, funcarray
, DOSBase
))
238 SetIoErr(ERROR_NO_FREE_STORE
);
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' ||
253 D(bug("[ELF Loader] Not an elf object\n"));
254 SetIoErr(ERROR_NOT_EXECUTABLE
);
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
291 # error Your architecture is not supported
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
));
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
));
320 SetIoErr(ERROR_OBJECT_WRONG_TYPE
);
330 BPTR
**next_hunk_ptr
,
333 struct DosLibrary
*DOSBase
339 if (ph
->memsz
< ph
->filesz
)
341 SetIoErr(ERROR_BAD_HUNK
);
348 hunk
= MyAlloc(ph
->memsz
+ sizeof(struct hunk
), MEMF_ANY
);
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
);
387 union aros_rel_entry
*rel
,
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
;
402 *((ULONG
*)&contents
[rel
++->offset
]) += addr_to_add
;
408 BPTR InternalLoadSeg_ELF_AROS
413 SIPTR
*stack __unused
,
414 struct MinList
*seginfos
,
415 struct DosLibrary
*DOSBase
419 struct sheader
*sh
= NULL
;
420 struct pheader
*ph
= NULL
;
423 BPTR
*next_hunk_ptr
= &hunks
;
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
))
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
))
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
;
459 /* We allow only one executable segment per object */
460 SetIoErr(ERROR_BAD_HUNK
);
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
472 SetIoErr(ERROR_BAD_HUNK
);
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
))
484 /* Finally, build the trampoline */
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
))
503 MyFree(sh
[i
].addr
, sh
[i
].size
);
514 /* There were some errors, deallocate the hunks */
516 InternalUnLoadSeg(hunks
, (VOID_FUNC
)funcarray
[2]);
521 /* Free the section headers */
523 MyFree(sh
, eh
.shnum
* eh
.shentsize
);
525 /* Free the program header */
527 MyFree(ph
, eh
.phnum
* eh
.phentsize
);