revert between 56095 -> 55830 in arch
[AROS.git] / arch / .unmaintained / m68k-pp-native / TxElf / myinternalloadseg_elf.c
blob8023c5a1d49c52bd31c0029d04db313d2a1fb744
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Code to dynamically load ELF executables and relocate it.
6 Take from dos/internalloadseg_elf.c
7 Lang: english
9 1997/12/13: Changed filename to internalloadseg_elf.c
10 Original file was created by digulla.
12 #include <exec/memory.h>
13 #include <proto/exec.h>
14 #include <dos/dosasl.h>
15 #include <proto/dos.h>
16 #include <proto/arossupport.h>
17 #include <aros/asmcall.h>
18 #include <aros/debug.h>
19 #include <string.h>
21 extern struct DosLibrary * DOSBase;
24 /* Debugging */
25 #define PRINT_SECTION_NAMES 1
26 #define PRINT_STRINGTAB 1
27 #define PRINT_SYMBOLTABLE 1
28 #define PRINT_SYMBOLS 1
29 #define LOAD_DEBUG_HUNKS 0
30 #define PRINT_SECTIONS 1
31 #define PRINT_HUNKS 1
32 #define DEBUG_HUNKS 0
34 #define SHT_PROGBITS 1
35 #define SHT_SYMTAB 2
36 #define SHT_STRTAB 3
37 #define SHT_RELA 4
38 #define SHT_NOBITS 8
39 #define SHT_REL 9
41 #define ET_REL 1
43 #define EM_68K 4
45 #define R_68K_32 1
46 #define R_68K_PC32 4
47 #define R_68K_PC16 5
49 #define STT_OBJECT 1
50 #define STT_FUNC 2
52 #define SHN_ABS 0xfff1
53 #define SHN_COMMON 0xfff2
54 #define SHN_UNDEF 0
56 #define ELF32_ST_TYPE(i) ((i) & 0x0F)
58 struct elfheader
60 UBYTE ident[16];
61 UWORD type;
62 UWORD machine;
63 ULONG version;
64 APTR entry;
65 ULONG phoff;
66 ULONG shoff;
67 ULONG flags;
68 UWORD ehsize;
69 UWORD phentsize;
70 UWORD phnum;
71 UWORD shentsize;
72 UWORD shnum;
73 UWORD shstrndx;
76 struct sheader
78 ULONG name;
79 ULONG type;
80 ULONG flags;
81 APTR addr;
82 ULONG offset;
83 ULONG size;
84 ULONG link;
85 ULONG info;
86 ULONG addralign;
87 ULONG entsize;
90 struct symbol
92 ULONG name; /* Offset of the name string in the string table */
93 ULONG value; /* Varies; eg. the offset of the symbol in its hunk */
94 ULONG size; /* How much memory does the symbol occupy */
95 UBYTE info; /* What kind of symbol is this ? (global, variable, etc) */
96 UBYTE other; /* undefined */
97 WORD shindex; /* In which section is the symbol defined ? */
100 struct relo
102 ULONG addr; /* Address of the relocation (relative to the last loaded hunk) */
103 ULONG info; /* Type of the relocation */
104 LONG addend; /* Constant addend used to compute value */
107 struct hunk
109 ULONG size; /* Size of the hunk */
110 UBYTE * memory; /* First actual byte in the memory of this machine */
111 ULONG destination; /* where it will be located on the destination device */
115 int read_block (BPTR file, ULONG offset, APTR buffer, ULONG size)
117 LONG subsize;
118 UBYTE * buf = (UBYTE *)buffer;
121 if (Seek (file, offset, OFFSET_BEGINNING) < 0) {
122 return 1;
125 while (size)
127 subsize = Read(file,buf,size);
129 if (subsize == 0)
131 ((struct Process *)FindTask (NULL))->pr_Result2 = ERROR_BAD_HUNK;
132 return 1;
135 if (subsize < 0)
136 return 1;
138 buf += subsize;
139 size -= subsize;
142 return 0;
143 } /* read_block */
145 BPTR MyInternalLoadSeg_ELF (BPTR file,
146 BPTR table,
147 LONG * stack,
148 struct IOExtSer * IORequest,
149 ULONG * startaddr)
152 /* Currently the only parameter passed to this function that is
153 actually used is file. The rest is there for completeness.
154 Functionarray will *soon* be used! */
156 struct elfheader eh;
157 UBYTE * shtab = NULL;
158 UBYTE * shstrtab = NULL;
159 UBYTE * strtab = NULL;
160 struct symbol * symtab = NULL;
161 struct hunk * hunks = NULL;
162 struct relo * reltab = NULL;
163 struct symbol * symbol;
164 struct sheader * sh = NULL; /* satisfy GCC */
166 ULONG numsym,
167 numrel,
169 WORD t,
170 mint = 0,
171 maxt = 0;
172 UBYTE * loaded, * destin;
173 BPTR last = 0;
174 LONG * error = &((struct Process *)FindTask (NULL))->pr_Result2;
176 #define ERROR(a) { *error = a; goto end; }
178 *error = 0;
180 /* Load the header */
181 if (read_block (file, 0, &eh, sizeof (eh)))
182 goto end;
184 /* Check the header of the file */
185 if ( eh.ident[0] != 0x7f
186 || eh.ident[1] != 'E'
187 || eh.ident[2] != 'L'
188 || eh.ident[3] != 'F'
190 ERROR (ERROR_NOT_EXECUTABLE);
192 /* Check file type and the CPU the file is for */
193 if (AROS_BE2WORD(eh.type) != ET_REL || AROS_BE2WORD(eh.machine) != EM_68K) {
194 ERROR (ERROR_OBJECT_WRONG_TYPE);
197 /* Get memory for section headers */
198 shtab = AllocVec (AROS_BE2WORD(eh.shentsize) * AROS_BE2WORD(eh.shnum), MEMF_ANY);
200 if (shtab == NULL)
201 ERROR (ERROR_NO_FREE_STORE);
203 /* Read section table */
204 if (read_block(file, AROS_BE2LONG(eh.shoff), shtab, AROS_BE2WORD(eh.shentsize) * AROS_BE2WORD(eh.shnum)))
205 goto end;
207 /* Look up the symbol table */
208 for (t=1; t<AROS_BE2WORD(eh.shnum); t++)
210 sh = (struct sheader *)(shtab + t*AROS_BE2WORD(eh.shentsize));
212 #if PRINT_SECTIONS
213 kprintf ("sh[%d] = { name=%d type=%d flags=%x addr=%p offset=%d "
214 "size=%d link=%d info=%d addralign=%d entsize=%d\n",
216 AROS_BE2LONG(sh->name),
217 AROS_BE2LONG(sh->type),
218 AROS_BE2LONG(sh->flags),
219 AROS_BE2LONG(sh->addr),
220 AROS_BE2LONG(sh->offset),
221 AROS_BE2LONG(sh->size),
222 AROS_BE2LONG(sh->link),
223 AROS_BE2LONG(sh->info),
224 AROS_BE2LONG(sh->addralign),
225 AROS_BE2LONG(sh->entsize));
226 #endif
228 if (AROS_BE2LONG(sh->type) == SHT_SYMTAB)
229 break;
232 if (t == AROS_BE2WORD(eh.shnum))
233 ERROR (ERROR_OBJECT_WRONG_TYPE);
235 /* Allocate memory for the symbol table */
236 symtab = AllocVec (AROS_BE2LONG(sh->size), MEMF_ANY);
238 if (symtab == NULL)
239 ERROR (ERROR_NO_FREE_STORE);
241 /* Read the symbol table */
242 if (read_block (file, AROS_BE2LONG(sh->offset), symtab, AROS_BE2LONG(sh->size)))
243 goto end;
245 numsym = AROS_BE2LONG(sh->size) / sizeof (struct symbol);
247 mint = maxt = AROS_BE2WORD(symtab[1].shindex);
249 /* kprintf ("Symbol %d: index=%d\n", 0, symtab[1].shindex); */
251 /* Find the minimal number of hunks which are neccessary to satisfy
252 all symbol references (ie. all hunks in which a symbol resides) */
253 for (i=2; i<numsym; i++)
255 #if PRINT_SYMBOLTABLE
256 kprintf ("Symbol %d: name=%d value=%d size=%d info=%d other=%d shindex=%d\n",
258 AROS_BE2LONG(symtab[i].name),
259 AROS_BE2LONG(symtab[i].value),
260 AROS_BE2LONG(symtab[i].size),
261 symtab[i].info,
262 symtab[i].other,
263 AROS_BE2WORD(symtab[i].shindex));
264 #endif
266 if ((WORD)AROS_BE2WORD(symtab[i].shindex) < mint) {
267 mint = AROS_BE2WORD(symtab[i].shindex);
269 if ((WORD)AROS_BE2WORD(symtab[i].shindex) > maxt) {
270 maxt = AROS_BE2WORD(symtab[i].shindex);
274 /* Allocate memory for information about every hunk */
275 hunks = AllocVec (sizeof (struct hunk) * (maxt - mint + 1), MEMF_CLEAR);
277 if (hunks == NULL)
278 ERROR (ERROR_NO_FREE_STORE);
280 /* Offset the base. Now I can simply access the first hunk as
281 hunks[t] instead of hunks[t-mint] */
282 hunks -= mint;
284 /* Load names of sections */
285 if (AROS_BE2WORD(eh.shstrndx))
287 sh = (struct sheader *)(shtab + AROS_BE2WORD(eh.shstrndx)*AROS_BE2WORD(eh.shentsize));
289 shstrtab = AllocVec (AROS_BE2LONG(sh->size), MEMF_ANY);
291 if (shstrtab == NULL)
292 ERROR (ERROR_NO_FREE_STORE);
294 if (read_block (file, AROS_BE2LONG(sh->offset), shstrtab, AROS_BE2LONG(sh->size)))
295 goto end;
297 #if PRINT_SECTION_NAMES
299 int n, t;
301 for (n=t=0; t<AROS_BE2LONG(sh->size); n++)
303 kprintf ("String %d@%d: \"%s\"\n", n, t, &shstrtab[t]);
304 t += strlen (&shstrtab[t]) + 1;
307 #endif
310 /* Find the basic size for each hunk */
311 for (t=1; t<AROS_BE2WORD(eh.shnum); t++)
313 sh = (struct sheader *)(shtab + t*AROS_BE2WORD(eh.shentsize));
316 // printf("This is %s\n",&shstrtab[AROS_BE2LONG(sh->name)]);
318 if (AROS_BE2LONG(sh->type) == SHT_PROGBITS || AROS_BE2LONG(sh->type) == SHT_NOBITS)
320 #if !LOAD_DEBUG_HUNKS
321 /* Don't load debug hunks */
322 if ( !strncmp (&shstrtab[AROS_BE2LONG(sh->name)], ".stab", 5)
323 || !strcmp (&shstrtab[AROS_BE2LONG(sh->name)], ".comment")
325 sh->size = 0;
326 #endif
328 hunks[t].size = AROS_BE2LONG(sh->size);
330 #if !LOAD_DEBUG_HUNKS
331 else if (AROS_BE2LONG(sh->type) == SHT_REL
332 && !strcmp (&shstrtab[AROS_BE2LONG(sh->name)], ".rel.stab")
334 sh->size = 0;
335 hunks[t].size = 0;
337 else if (AROS_BE2LONG(sh->type) == SHT_RELA
338 && !strcmp (&shstrtab[AROS_BE2LONG(sh->name)], ".rela.stab")
340 sh->size = 0;
341 hunks[t].size = 0;
342 } else {
343 printf("\tIgnoring %s\n",&shstrtab[AROS_BE2LONG(sh->name)]);
345 #endif
348 /* Look for names of symbols */
349 for (t=AROS_BE2WORD(eh.shnum); t>0; t--)
351 sh = (struct sheader *)(shtab + t*AROS_BE2WORD(eh.shentsize));
353 if (AROS_BE2LONG(sh->type) == SHT_STRTAB)
354 break;
357 /* Found the section with the names ? Load the symbols' names */
358 if (t)
360 strtab = AllocVec (AROS_BE2LONG(sh->size), MEMF_ANY);
362 if (strtab == NULL)
363 ERROR (ERROR_NO_FREE_STORE);
365 /* kprintf ("Reading StrTab at %d (offset=%ld, size=%ld)\n", eh.shstrndx, sh->offset, sh->size); */
367 if (read_block (file, AROS_BE2LONG(sh->offset), strtab, AROS_BE2LONG(sh->size)))
368 goto end;
370 #if PRINT_STRINGTAB
372 int n, t;
374 for (n=t=0; t<AROS_BE2LONG(sh->size); n++)
376 kprintf ("String %d@%d: \"%s\"\n", n, t, &strtab[t]);
377 t += strlen (&strtab[t]) + 1;
380 #endif
383 kprintf (" File has %d sections.\n", AROS_BE2WORD(eh.shnum));
385 /* Reserve memory for each global symbol in its hunk */
386 for (i=1; i<numsym; i++)
388 if ((WORD)AROS_BE2WORD(symtab[i].shindex) < 0)
390 symtab[i].value = AROS_BE2LONG(hunks[AROS_BE2WORD(symtab[i].shindex)].size);
391 hunks[AROS_BE2WORD(symtab[i].shindex)].size += AROS_BE2LONG(symtab[i].size);
393 else if (AROS_BE2WORD(symtab[i].shindex == SHN_UNDEF))
395 kprintf ("Symbol %s is undefined\n",
396 &strtab[AROS_BE2LONG(symtab[i].name)]);
398 ERROR (ERROR_OBJECT_WRONG_TYPE);
402 /* Allocate memory for each segment */
403 for (t=mint; t<=maxt; t++)
405 /* Don't allocate memory for hunks which don't need any */
406 if (hunks[t].size)
408 hunks[t].memory = AllocMem(hunks[t].size+sizeof(ULONG)+sizeof(BPTR),MEMF_CLEAR);
409 hunks[t].destination = GetPilotMem(hunks[t].size);
411 if (hunks[t].memory == NULL)
412 ERROR (ERROR_NO_FREE_STORE);
414 if (hunks[t].destination == NULL) {
415 printf("Not enough memory to hold AROS on the Palm (TM) device!\n");
418 *((BPTR *)(hunks[t].memory)) = (BPTR)(hunks[t].size + sizeof(ULONG) + sizeof(BPTR));
420 hunks[t].memory += sizeof(ULONG) + sizeof(BPTR);
425 #if PRINT_SYMBOLS
426 /* Show the final addresses of global symbols */
427 if (strtab)
429 for (i=1; i<numsym; i++)
431 /* Print the symbol if it has a name and if it's a variable
432 or function */
433 if (strtab[AROS_BE2LONG(symtab[i].name)]
434 && (
435 ELF32_ST_TYPE(symtab[i].info) == STT_OBJECT
436 || ELF32_ST_TYPE(symtab[i].info) == STT_FUNC
440 if (!strcmp ("entry", &strtab[AROS_BE2LONG(symtab[i].name)]))
442 kprintf (" Symbol at 0x%p: %s\n"
443 , hunks[AROS_BE2WORD(symtab[i].shindex)].memory + AROS_BE2LONG(symtab[i].value)
444 , &strtab[AROS_BE2LONG(symtab[i].name)]
447 /* Print only this symbol */
448 break;
453 #endif
455 loaded = NULL;
457 /* Now load the pieces into memory */
458 for (t=1; t<AROS_BE2WORD(eh.shnum); t++)
460 sh = (struct sheader *)(shtab + t*AROS_BE2WORD(eh.shentsize));
462 #if PRINT_HUNKS
463 kprintf ("sh=%s hunk[%d] = { size=%d (%d) memory=%p, &hunk[%d]=%p }\n",
464 &shstrtab[AROS_BE2LONG(sh->name)],
466 hunks[t].size, AROS_BE2LONG(sh->size),
467 hunks[t].memory, t, &hunks[t]);
468 #endif
470 if (!AROS_BE2LONG(sh->size))
471 continue;
473 switch(AROS_BE2LONG(sh->type))
475 case SHT_PROGBITS: /* Code */
476 printf("hunks[%d] is code.\n",t);
477 if (read_block (file, AROS_BE2LONG(sh->offset), hunks[t].memory, AROS_BE2LONG(sh->size)))
478 goto end;
480 loaded = hunks[t].memory;
481 destin = hunks[t].destination;
483 #if DEBUG_HUNKS
484 if (strtab
485 /* && (
486 !strcmp (".text", &shstrtab[AROS_BE2LONG(sh->name)])
487 || !strcmp (".rodata", &shstrtab[AROS_BE2LONG(sh->name)])
488 || !strcmp (".data", &shstrtab[AROS_BE2LONG(sh->name)])
489 ) */
492 kprintf (" Section at 0x%p ... 0x%p: %s\n"
493 , loaded
494 , loaded + AROS_BE2LONG(sh->size) - 1
495 , &shstrtab[AROS_BE2LONG(sh->name)]
498 #endif
500 break;
502 case SHT_RELA:
503 case SHT_REL: /* Relocation table */
505 if (loaded == NULL)
506 ERROR (ERROR_OBJECT_WRONG_TYPE);
508 /* Get memory for the relocation table */
509 reltab = AllocVec (AROS_BE2LONG(sh->size), MEMF_ANY);
511 if (reltab == NULL)
512 ERROR (ERROR_NO_FREE_STORE);
514 /* Load it */
515 if (read_block (file, AROS_BE2LONG(sh->offset), reltab, AROS_BE2LONG(sh->size)))
516 goto end;
518 numrel = AROS_BE2LONG(sh->size) / sizeof (struct relo);
520 /* For each relocation ... */
522 kprintf("Relocating %d items. (%d/%d)\n",numrel,AROS_BE2LONG(sh->size),sizeof (struct relo));
523 for (i=0; i<numrel; i++)
525 symbol = &symtab[AROS_BE2LONG(reltab[i].info) >> 8];
527 kprintf("symbol->shindex: %d,hunks[...].memory=%x\n",
528 AROS_BE2WORD(symbol->shindex),
529 (ULONG)hunks[AROS_BE2WORD(symbol->shindex)].memory);
531 switch (AROS_BE2LONG(reltab[i].info) & 0xFF)
533 case R_68K_32:
534 kprintf("R_68K_32! %x,symbol->value: %x,added: %x\n",AROS_BE2LONG(reltab[i].addr),AROS_BE2LONG(symbol->value),AROS_BE2LONG(reltab[i].addend));
536 *(ULONG *)&loaded[AROS_BE2LONG(reltab[i].addr)] =
537 AROS_BE2LONG(hunks[AROS_BE2WORD(symbol->shindex)].destination +
538 AROS_BE2LONG(symbol->value) +
539 AROS_BE2LONG(reltab[i].addend));
540 break;
542 case R_68K_PC32:
543 kprintf("R_68K_PC32! %x,symbol->value: %x\n",AROS_BE2LONG(reltab[i].addr),AROS_BE2LONG(symbol->value),AROS_BE2LONG(reltab[i].addend));
545 *(ULONG *)&loaded[AROS_BE2LONG(reltab[i].addr)] =
546 AROS_BE2LONG(hunks[AROS_BE2WORD(symbol->shindex)].destination +
547 AROS_BE2LONG(symbol->value) +
548 AROS_BE2LONG(reltab[i].addend) -
549 (ULONG)&destin[AROS_BE2LONG(reltab[i].addr)]);
551 #if 0
552 printf("reltab[%d].addr=%x\n",i,AROS_BE2LONG(reltab[i].addr));
553 printf("hunks[%d].destination = %x\n",
554 AROS_BE2WORD(symbol->shindex),
555 hunks[AROS_BE2WORD(symbol->shindex)].destination);
556 printf("symbol->value: %x\n",AROS_BE2LONG(symbol->value));
557 printf("reltab[%d].addend: %x\n",i,AROS_BE2LONG(reltab[i].addend));
558 printf("&destin[reltab[i].addr]=%x\n",(ULONG)&destin[AROS_BE2LONG(reltab[i].addr)]);
559 #endif
560 break;
562 case R_68K_PC16:
563 kprintf("\t\tR_68K_PC16 not implemented, yet!\n");
564 kprintf("R_68K_PC16! %x,symbol->value: %x\n",AROS_BE2LONG(reltab[i].addr),AROS_BE2LONG(symbol->value));
565 /* is this correct? */
567 *(UWORD *)&loaded[AROS_BE2LONG(reltab[i].addr)] =
568 AROS_BE2WORD(hunks[AROS_BE2WORD(symbol->shindex)].destination +
569 AROS_BE2LONG(symbol->value) +
570 AROS_BE2LONG(reltab[i].addend) -
571 (ULONG)&destin[AROS_BE2LONG(reltab[i].addr)]);
572 break;
574 default:
575 kprintf("Unknown relocation type %d!\n",AROS_BE2LONG(reltab[i].info) & 0xFF);
576 ERROR (ERROR_BAD_HUNK);
577 } /* switch */
578 } /* for */
580 /* Release memory */
581 FreeVec (reltab);
582 reltab = NULL;
583 loaded = NULL;
585 break;
587 default:
588 printf("Untreated type: %d\n",AROS_BE2LONG(sh->type));
589 } /* switch */
592 /* link hunks */
593 for (t=mint; t<0; t++)
595 if (hunks[t].size)
597 ((BPTR *)hunks[t].memory)[-1] = last;
598 last = MKBADDR((BPTR *)hunks[t].memory - 1);
599 printf("Sending code of size %d(0x%x), hunk %d, destination address 0x%x.\n",hunks[t].size,hunks[t].size,t,hunks[t].destination);
600 send_chunk(IORequest, hunks[t].destination, hunks[t].memory,hunks[t].size);
601 *startaddr = hunks[t].destination;
605 for (t=maxt; t>=0; t--)
607 if (hunks[t].size)
609 ((BPTR *)hunks[t].memory)[-1] = last;
610 last = MKBADDR((BPTR *)hunks[t].memory-1);
611 printf("Sending code of size %d(0x%x), hunk %d, destination address 0x%x.\n",hunks[t].size,hunks[t].size,t,hunks[t].destination);
612 send_chunk(IORequest, hunks[t].destination, hunks[t].memory,hunks[t].size);
613 *startaddr = hunks[t].destination;
616 #warning Must also free all code here!
617 /* Free hunk information table */
618 FreeVec (hunks+mint);
620 hunks = NULL;
622 end:
623 FreeVec (reltab);
625 /* Free all hunks, too ? */
626 if (hunks != NULL)
628 for (t=mint; t<=maxt; t++)
630 if (hunks[t].memory != NULL)
632 FreeMem(hunks[t].memory-sizeof(BPTR)-sizeof(ULONG),
633 hunks[t].size +sizeof(BPTR)+sizeof(ULONG));
638 FreeVec (hunks + mint);
640 /* Fail */
641 last = NULL;
643 if (shstrtab)
644 FreeVec (shstrtab);
646 if (strtab)
647 FreeVec (strtab);
649 FreeVec (symtab);
650 FreeVec (shtab);
652 return last;
653 } /* LoadSeg_ELF */