2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
5 Desc: Code to dynamically load ELF executables and relocate it.
6 Take from dos/internalloadseg_elf.c
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>
21 extern struct DosLibrary
* DOSBase
;
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
34 #define SHT_PROGBITS 1
52 #define SHN_ABS 0xfff1
53 #define SHN_COMMON 0xfff2
56 #define ELF32_ST_TYPE(i) ((i) & 0x0F)
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 ? */
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 */
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
)
118 UBYTE
* buf
= (UBYTE
*)buffer
;
121 if (Seek (file
, offset
, OFFSET_BEGINNING
) < 0) {
127 subsize
= Read(file
,buf
,size
);
131 ((struct Process
*)FindTask (NULL
))->pr_Result2
= ERROR_BAD_HUNK
;
145 BPTR
MyInternalLoadSeg_ELF (BPTR file
,
148 struct IOExtSer
* IORequest
,
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! */
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 */
172 UBYTE
* loaded
, * destin
;
174 LONG
* error
= &((struct Process
*)FindTask (NULL
))->pr_Result2
;
176 #define ERROR(a) { *error = a; goto end; }
180 /* Load the header */
181 if (read_block (file
, 0, &eh
, sizeof (eh
)))
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
);
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
)))
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
));
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
));
228 if (AROS_BE2LONG(sh
->type
) == SHT_SYMTAB
)
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
);
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
)))
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
),
263 AROS_BE2WORD(symtab
[i
].shindex
));
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
);
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] */
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
)))
297 #if PRINT_SECTION_NAMES
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;
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")
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")
337 else if (AROS_BE2LONG(sh
->type
) == SHT_RELA
338 && !strcmp (&shstrtab
[AROS_BE2LONG(sh
->name
)], ".rela.stab")
343 printf("\tIgnoring %s\n",&shstrtab
[AROS_BE2LONG(sh
->name
)]);
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
)
357 /* Found the section with the names ? Load the symbols' names */
360 strtab
= AllocVec (AROS_BE2LONG(sh
->size
), MEMF_ANY
);
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
)))
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;
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 */
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
);
426 /* Show the final addresses of global symbols */
429 for (i
=1; i
<numsym
; i
++)
431 /* Print the symbol if it has a name and if it's a variable
433 if (strtab
[AROS_BE2LONG(symtab
[i
].name
)]
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 */
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
));
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
]);
470 if (!AROS_BE2LONG(sh
->size
))
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
)))
480 loaded
= hunks
[t
].memory
;
481 destin
= hunks
[t
].destination
;
486 !strcmp (".text", &shstrtab[AROS_BE2LONG(sh->name)])
487 || !strcmp (".rodata", &shstrtab[AROS_BE2LONG(sh->name)])
488 || !strcmp (".data", &shstrtab[AROS_BE2LONG(sh->name)])
492 kprintf (" Section at 0x%p ... 0x%p: %s\n"
494 , loaded
+ AROS_BE2LONG(sh
->size
) - 1
495 , &shstrtab
[AROS_BE2LONG(sh
->name
)]
503 case SHT_REL
: /* Relocation table */
506 ERROR (ERROR_OBJECT_WRONG_TYPE
);
508 /* Get memory for the relocation table */
509 reltab
= AllocVec (AROS_BE2LONG(sh
->size
), MEMF_ANY
);
512 ERROR (ERROR_NO_FREE_STORE
);
515 if (read_block (file
, AROS_BE2LONG(sh
->offset
), reltab
, AROS_BE2LONG(sh
->size
)))
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)
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
));
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
)]);
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
)]);
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
)]);
575 kprintf("Unknown relocation type %d!\n",AROS_BE2LONG(reltab
[i
].info
) & 0xFF);
576 ERROR (ERROR_BAD_HUNK
);
588 printf("Untreated type: %d\n",AROS_BE2LONG(sh
->type
));
593 for (t
=mint
; t
<0; t
++)
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
--)
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
);
625 /* Free all hunks, too ? */
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
);