2 /* --------------------------------------------------------------------------
3 * Machinery for dynamic loading and linking of object code. Should be
4 * completely independent from the rest of Hugs so we can use it in
5 * other applications if desired.
7 * The Hugs 98 system is Copyright (c) Mark P Jones, Alastair Reid, the
8 * Yale Haskell Group, and the Oregon Graduate Institute of Science and
9 * Technology, 1994-1999, All rights reserved. It is distributed as
10 * free software under the license in the file "License", which is
11 * included in the distribution.
13 * ------------------------------------------------------------------------*/
19 #include "config.h" /* for linux_TARGET_OS etc */
23 #if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
24 static int ocVerifyImage_ELF ( ObjectCode* oc, int verb );
25 static int ocGetNames_ELF ( ObjectCode* oc, int verb );
26 static int ocResolve_ELF ( ObjectCode* oc, int verb );
29 static char* hackyAppend ( char* s1, char* s2 );
32 /* --------------------------------------------------------------------------
33 * Arch-independent interface to the runtime linker
34 * ------------------------------------------------------------------------*/
36 ObjectCode* ocNew ( void (*errMsg)(char*),
37 void* (*clientLookup)(char*),
41 ObjectCode* oc = malloc(sizeof(ObjectCode));
43 errMsg("ocNew: can't allocate memory for object code record");
47 # if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
48 oc->formatName = "ELF";
51 errMsg("ocNew: not implemented on this platform");
55 oc->status = OBJECT_NOTINUSE;
56 oc->objFileName = objFileName;
57 oc->objFileSize = objFileSize;
59 oc->clientLookup = clientLookup;
61 oc->oImage = malloc ( objFileSize );
64 errMsg("ocNew: can't allocate memory for object code");
70 oc->sectionTab = NULL;
71 oc->sizesectionTab = 0;
72 oc->usedsectionTab = 0;
79 int ocLoadImage ( ObjectCode* oc, int verb )
83 assert (oc && oc->status==OBJECT_NOTINUSE);
84 if (verb) fprintf(stderr, "ocLoadImage %s\n", oc->objFileName );
85 f = fopen(oc->objFileName, "rb");
87 (oc->errMsg(hackyAppend("ocLoadImage: can't read: ",
91 n = fread ( oc->oImage, 1, oc->objFileSize, f );
92 if (n != oc->objFileSize) {
94 oc->errMsg(hackyAppend("ocLoadImage: I/O error whilst reading: ",
98 oc->status = OBJECT_OIMAGE;
99 if (verb) fprintf(stderr, "ocLoadImage %s: read %d bytes\n",
100 oc->objFileName, oc->objFileSize );
105 /* returns 1 if ok, 0 if error */
106 int ocVerifyImage ( ObjectCode* oc, int verb )
109 assert (oc && oc->status==OBJECT_OIMAGE);
110 if (verb) fprintf(stderr, "ocVerifyImage: begin\n");
111 # if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
112 ret = ocVerifyImage_ELF ( oc, verb );
114 oc->errMsg("ocVerifyImage: not implemented on this platform");
117 if (verb) fprintf(stderr, "ocVerifyImage: done, status = %d", ret);
119 if (ret) oc->status = OBJECT_VERIFIED;
124 /* returns 1 if ok, 0 if error */
125 int ocGetNames ( ObjectCode* oc, int verb )
128 assert (oc && oc->status==OBJECT_VERIFIED);
129 if (verb) fprintf(stderr, "ocGetNames: begin\n");
130 # if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
131 ret = ocGetNames_ELF ( oc, verb );
133 oc->errMsg("ocGetNames: not implemented on this platform");
136 if (verb) fprintf(stderr, "ocGetNames: done, status = %d\n", ret);
137 if (ret) oc->status = OBJECT_HAVENAMES;
142 /* returns 1 if ok, 0 if error */
143 int ocResolve ( ObjectCode* oc, int verb )
146 assert (oc && oc->status==OBJECT_HAVENAMES);
147 if (verb) fprintf(stderr, "ocResolve: begin\n");
148 # if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
149 ret = ocResolve_ELF ( oc, verb );
151 oc->errMsg("ocResolve: not implemented on this platform");
154 if (verb) fprintf(stderr, "ocResolve: done, status = %d\n", ret);
155 if (ret) oc->status = OBJECT_RESOLVED;
160 void ocFree ( ObjectCode* oc )
163 if (oc->oImage) free(oc->oImage);
164 if (oc->oTab) free(oc->oTab);
165 if (oc->sectionTab) free(oc->sectionTab);
171 /* --------------------------------------------------------------------------
172 * Simple, dynamically expandable association tables
173 * ------------------------------------------------------------------------*/
175 /* A bit tricky. Assumes that if tab==NULL, then
176 currUsed and *currSize must be zero.
177 Returns NULL if expansion failed.
179 static void* genericExpand ( void* tab,
180 int* currSize, int currUsed,
181 int initSize, int elemSize )
185 if (currUsed < *currSize) return tab;
186 size2 = (*currSize == 0) ? initSize : (2 * *currSize);
187 tab2 = malloc ( size2 * elemSize );
188 if (!tab2) return NULL;
190 memcpy ( tab2, tab, elemSize * *currSize );
192 if (tab) free ( tab );
197 /* returns 1 if success, 0 if error */
198 static int addSymbol ( ObjectCode* oc, char* nm, void* ad )
201 = genericExpand ( oc->oTab,
207 oc->errMsg("addSymbol: malloc failed whilst expanding table");
211 oc->oTab[ oc->usedoTab ].nm = nm;
212 oc->oTab[ oc->usedoTab ].ad = ad;
218 /* returns 1 if success, 0 if error */
219 static int addSection ( ObjectCode* oc, void* start, void* end, OSectionKind sect )
222 = genericExpand ( oc->sectionTab,
223 &(oc->sizesectionTab),
225 4, sizeof(OSection) );
227 oc->errMsg("addSection: malloc failed whilst expanding table");
230 oc->sectionTab = newTab;
231 oc->sectionTab[ oc->usedsectionTab ].start = start;
232 oc->sectionTab[ oc->usedsectionTab ].end = end;
233 oc->sectionTab[ oc->usedsectionTab ].kind = sect;
234 oc->usedsectionTab++;
239 void* ocLookupSym ( ObjectCode* oc, char* sym )
244 if (oc->status != OBJECT_HAVENAMES
245 && oc->status != OBJECT_RESOLVED) {
246 oc->errMsg("ocLookupSym: no symbols available");
250 for (i = 0; i < oc->usedoTab; i++) {
253 "ocLookupSym: request %s, table has %s\n",
254 sym, oc->oTab[i].nm );
255 if (0==strcmp(sym,oc->oTab[i].nm))
256 return oc->oTab[i].ad;
262 char* ocLookupAddr ( ObjectCode* oc, void* addr )
267 if (oc->status != OBJECT_HAVENAMES
268 && oc->status != OBJECT_RESOLVED) {
269 oc->errMsg("ocLookupAddr: no symbols available");
273 for (i = 0; i < oc->usedoTab; i++) {
274 if (addr == oc->oTab[i].ad)
275 return oc->oTab[i].nm;
281 OSectionKind ocLookupSection ( ObjectCode* oc, void* addr )
286 if (oc->status != OBJECT_HAVENAMES
287 && oc->status != OBJECT_RESOLVED) {
288 oc->errMsg("ocLookupSection: no symbols available");
289 return HUGS_SECTIONKIND_NOINFOAVAIL;
293 for (i = 0; i < oc->usedsectionTab; i++) {
294 if (oc->sectionTab[i].start <= addr
295 && addr <= oc->sectionTab[i].end)
296 return oc->sectionTab[i].kind;
299 return HUGS_SECTIONKIND_NOINFOAVAIL;
303 /* Ghastly append which leaks space. But we only use it for
304 error messages -- that's my excuse.
306 static char* hackyAppend ( char* s1, char* s2 )
308 char* res = malloc ( 4 + strlen(s1) + strlen(s2) );
310 fprintf ( stderr, "hugs: fatal: hackyAppend\n\t%s\n\t%s\n", s1, s2 );
318 /* --------------------------------------------------------------------------
320 * ------------------------------------------------------------------------*/
325 #if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
329 static char* findElfSection ( void* objImage, Elf32_Word sh_type )
332 char* ehdrC = (char*)objImage;
333 Elf32_Ehdr* ehdr = ( Elf32_Ehdr*)ehdrC;
334 Elf32_Shdr* shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
336 for (i = 0; i < ehdr->e_shnum; i++) {
337 if (shdr[i].sh_type == sh_type &&
338 i != ehdr->e_shstrndx) {
339 ptr = ehdrC + shdr[i].sh_offset;
347 static int ocVerifyImage_ELF ( ObjectCode* oc, int verb )
351 int i, j, nent, nstrtab, nsymtabs;
355 char* ehdrC = (char*)(oc->oImage);
356 Elf32_Ehdr* ehdr = ( Elf32_Ehdr*)ehdrC;
358 if (ehdr->e_ident[EI_MAG0] != ELFMAG0 ||
359 ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
360 ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
361 ehdr->e_ident[EI_MAG3] != ELFMAG3) {
362 oc->errMsg("Not an ELF header");
365 if (verb) fprintf ( stderr, "Is an ELF header\n" );
367 if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) {
368 oc->errMsg("Not 32 bit ELF" );
371 if (verb) fprintf ( stderr, "Is 32 bit ELF\n" );
373 if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) {
374 if (verb) fprintf ( stderr, "Is little-endian\n" );
376 if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) {
377 if (verb) fprintf ( stderr, "Is big-endian\n" );
379 oc->errMsg("Unknown endiannness");
383 if (ehdr->e_type != ET_REL) {
384 oc->errMsg("Not a relocatable object (.o) file");
387 if (verb) fprintf ( stderr, "Is a relocatable object (.o) file\n" );
389 if (verb) fprintf ( stderr, "Architecture is " );
390 switch (ehdr->e_machine) {
391 case EM_386: if (verb) fprintf ( stderr, "x86\n" ); break;
392 case EM_SPARC: if (verb) fprintf ( stderr, "sparc\n" ); break;
393 default: if (verb) fprintf ( stderr, "unknown\n" );
394 oc->errMsg("Unknown architecture");
400 "\nSection header table: start %d, n_entries %d, ent_size %d\n",
401 ehdr->e_shoff, ehdr->e_shnum, ehdr->e_shentsize );
403 assert (ehdr->e_shentsize == sizeof(Elf32_Shdr));
405 shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
407 if (ehdr->e_shstrndx == SHN_UNDEF) {
408 oc->errMsg("No section header string table");
411 if (verb) fprintf ( stderr,"Section header string table is section %d\n",
413 sh_strtab = ehdrC + shdr[ehdr->e_shstrndx].sh_offset;
416 for (i = 0; i < ehdr->e_shnum; i++) {
417 if (verb) fprintf ( stderr, "%2d: ", i );
418 if (verb) fprintf ( stderr, "type=%2d ", shdr[i].sh_type );
419 if (verb) fprintf ( stderr, "size=%4d ", shdr[i].sh_size );
420 if (verb) fprintf ( stderr, "offs=%4d ", shdr[i].sh_offset );
421 if (verb) fprintf ( stderr, " (%p .. %p) ",
422 ehdrC + shdr[i].sh_offset,
423 ehdrC + shdr[i].sh_offset + shdr[i].sh_size - 1);
425 if (shdr[i].sh_type == SHT_REL && verb) fprintf ( stderr, "Rel " ); else
426 if (shdr[i].sh_type == SHT_RELA && verb) fprintf ( stderr, "RelA " ); else
427 if (verb) fprintf ( stderr, " " );
428 if (sh_strtab && verb)
429 fprintf ( stderr, "sname=%s", sh_strtab + shdr[i].sh_name );
430 if (verb) fprintf ( stderr, "\n" );
433 if (verb) fprintf ( stderr, "\n\nString tables\n" );
436 for (i = 0; i < ehdr->e_shnum; i++) {
437 if (shdr[i].sh_type == SHT_STRTAB &&
438 i != ehdr->e_shstrndx) {
440 fprintf ( stderr, " section %d is a normal string table\n", i );
441 strtab = ehdrC + shdr[i].sh_offset;
446 oc->errMsg("WARNING: no string tables, or too many");
451 if (verb) fprintf ( stderr, "\n\nSymbol tables\n" );
452 for (i = 0; i < ehdr->e_shnum; i++) {
453 if (shdr[i].sh_type != SHT_SYMTAB) continue;
454 if (verb) fprintf ( stderr, "section %d is a symbol table\n", i );
456 stab = (Elf32_Sym*) (ehdrC + shdr[i].sh_offset);
457 nent = shdr[i].sh_size / sizeof(Elf32_Sym);
458 if (verb) fprintf ( stderr, " number of entries is apparently %d (%d rem)\n",
460 shdr[i].sh_size % sizeof(Elf32_Sym)
462 if (0 != shdr[i].sh_size % sizeof(Elf32_Sym)) {
463 oc->errMsg("non-integral number of symbol table entries");
466 for (j = 0; j < nent; j++) {
467 if (verb) fprintf ( stderr, " %2d ", j );
468 if (verb) fprintf ( stderr, " sec=%-5d size=%-3d val=%-5p ",
469 (int)stab[j].st_shndx,
470 (int)stab[j].st_size,
471 (char*)stab[j].st_value );
473 if (verb) fprintf ( stderr, "type=" );
474 switch (ELF32_ST_TYPE(stab[j].st_info)) {
475 case STT_NOTYPE: if (verb) fprintf ( stderr, "notype " ); break;
476 case STT_OBJECT: if (verb) fprintf ( stderr, "object " ); break;
477 case STT_FUNC : if (verb) fprintf ( stderr, "func " ); break;
478 case STT_SECTION: if (verb) fprintf ( stderr, "section" ); break;
479 case STT_FILE: if (verb) fprintf ( stderr, "file " ); break;
480 default: if (verb) fprintf ( stderr, "? " ); break;
482 if (verb) fprintf ( stderr, " " );
484 if (verb) fprintf ( stderr, "bind=" );
485 switch (ELF32_ST_BIND(stab[j].st_info)) {
486 case STB_LOCAL : if (verb) fprintf ( stderr, "local " ); break;
487 case STB_GLOBAL: if (verb) fprintf ( stderr, "global" ); break;
488 case STB_WEAK : if (verb) fprintf ( stderr, "weak " ); break;
489 default: if (verb) fprintf ( stderr, "? " ); break;
491 if (verb) fprintf ( stderr, " " );
493 if (verb) fprintf ( stderr, "name=%s\n", strtab + stab[j].st_name );
498 oc->errMsg("Didn't find any symbol tables");
506 static int ocGetNames_ELF ( ObjectCode* oc, int verb )
511 char* ehdrC = (char*)(oc->oImage);
512 Elf32_Ehdr* ehdr = (Elf32_Ehdr*)ehdrC;
513 char* strtab = findElfSection ( ehdrC, SHT_STRTAB );
514 Elf32_Shdr* shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
515 char* sh_strtab = ehdrC + shdr[ehdr->e_shstrndx].sh_offset;
518 oc->errMsg("no strtab!");
523 for (i = 0; i < ehdr->e_shnum; i++) {
525 /* make a HugsDLSection entry for relevant sections */
526 OSectionKind kind = HUGS_SECTIONKIND_OTHER;
527 if (0==strcmp(".data",sh_strtab+shdr[i].sh_name) ||
528 0==strcmp(".data1",sh_strtab+shdr[i].sh_name))
529 kind = HUGS_SECTIONKIND_RWDATA;
530 if (0==strcmp(".text",sh_strtab+shdr[i].sh_name) ||
531 0==strcmp(".rodata",sh_strtab+shdr[i].sh_name) ||
532 0==strcmp(".rodata1",sh_strtab+shdr[i].sh_name))
533 kind = HUGS_SECTIONKIND_CODE_OR_RODATA;
534 if (kind != HUGS_SECTIONKIND_OTHER)
537 ehdrC + shdr[i].sh_offset,
538 ehdrC + shdr[i].sh_offset + shdr[i].sh_size - 1,
542 if (shdr[i].sh_type != SHT_SYMTAB) continue;
544 /* copy stuff into this module's object symbol table */
545 stab = (Elf32_Sym*) (ehdrC + shdr[i].sh_offset);
546 nent = shdr[i].sh_size / sizeof(Elf32_Sym);
547 for (j = 0; j < nent; j++) {
548 if ( ( ELF32_ST_BIND(stab[j].st_info)==STB_GLOBAL ||
549 ELF32_ST_BIND(stab[j].st_info)==STB_LOCAL
552 ( ELF32_ST_TYPE(stab[j].st_info)==STT_FUNC ||
553 ELF32_ST_TYPE(stab[j].st_info)==STT_OBJECT)
554 /* || ELF32_ST_TYPE(stab[j].st_info)==STT_NOTYPE */
556 char* nm = strtab + stab[j].st_name;
558 + shdr[ stab[j].st_shndx ].sh_offset
563 fprintf(stderr, "addOTabName: %10p %s %s\n",
564 ad, oc->objFileName, nm );
565 addSymbol ( oc, nm, ad );
567 else fprintf(stderr, "skipping `%s'\n", strtab + stab[j].st_name );
574 static int ocResolve_ELF ( ObjectCode* oc, int verb )
576 char symbol[1000]; // ToDo
579 Elf32_Sym* stab = NULL;
580 char* ehdrC = (char*)(oc->oImage);
581 Elf32_Ehdr* ehdr = (Elf32_Ehdr*) ehdrC;
582 Elf32_Shdr* shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
585 /* first find "the" symbol table */
586 stab = (Elf32_Sym*) findElfSection ( ehdrC, SHT_SYMTAB );
588 /* also go find the string table */
589 strtab = findElfSection ( ehdrC, SHT_STRTAB );
591 if (!stab || !strtab) {
592 oc->errMsg("can't find string or symbol table");
596 for (i = 0; i < ehdr->e_shnum; i++) {
597 if (shdr[i].sh_type == SHT_REL ) {
598 Elf32_Rel* rtab = (Elf32_Rel*) (ehdrC + shdr[i].sh_offset);
599 int nent = shdr[i].sh_size / sizeof(Elf32_Rel);
600 int target_shndx = shdr[i].sh_info;
601 int symtab_shndx = shdr[i].sh_link;
602 stab = (Elf32_Sym*) (ehdrC + shdr[ symtab_shndx ].sh_offset);
603 targ = (Elf32_Word*)(ehdrC + shdr[ target_shndx ].sh_offset);
606 "relocations for section %d using symtab %d\n",
607 target_shndx, symtab_shndx );
608 for (j = 0; j < nent; j++) {
609 Elf32_Addr offset = rtab[j].r_offset;
610 Elf32_Word info = rtab[j].r_info;
612 Elf32_Addr P = ((Elf32_Addr)targ) + offset;
613 Elf32_Word* pP = (Elf32_Word*)P;
617 if (verb) fprintf ( stderr, "Rel entry %3d is raw(%6p %6p) ",
618 j, (void*)offset, (void*)info );
620 if (verb) fprintf ( stderr, " ZERO\n" );
623 /* First see if it is a nameless local symbol. */
624 if (stab[ ELF32_R_SYM(info)].st_name == 0) {
625 if (verb) fprintf ( stderr, "(noname) ");
626 S = (Elf32_Addr)(ehdrC
627 + shdr[stab[ELF32_R_SYM(info)].st_shndx ].sh_offset
628 + stab[ELF32_R_SYM(info)].st_value
630 strcpy ( symbol, "(noname)");
632 /* No? Perhaps it's a named symbol in this file. */
633 strcpy ( symbol, strtab+stab[ ELF32_R_SYM(info)].st_name );
634 if (verb) fprintf ( stderr, "`%s' ", symbol );
635 S = (Elf32_Addr)ocLookupSym ( oc, symbol );
637 /* No? Ok, too hard. Hand the problem to the client.
638 And if that fails, we're outta options.
640 S = (Elf32_Addr)(oc->clientLookup ( symbol ) );
643 if (verb) fprintf ( stderr, "resolves to %p\n", (void*)S );
646 strcpy(errtxt,oc->objFileName);
647 strcat(errtxt,": unresolvable reference to: ");
648 strcat(errtxt,symbol);
653 /* fprintf ( stderr, "Reloc: P = %p S = %p A = %p\n\n",
654 (void*)P, (void*)S, (void*)A );
656 switch (ELF32_R_TYPE(info)) {
657 case R_386_32: *pP = S + A; break;
658 case R_386_PC32: *pP = S + A - P; break;
659 default: fprintf(stderr,
660 "unhandled ELF relocation type %d\n",
662 oc->errMsg("unhandled ELF relocation type");
669 if (shdr[i].sh_type == SHT_RELA) {
670 oc->errMsg("RelA style reloc table -- not yet done");
679 #endif /* defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS) */
683 /*-------------------------------------------------------------------------*/