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 * ------------------------------------------------------------------------*/
22 #if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
23 static int ocVerifyImage_ELF ( ObjectCode* oc, int verb );
24 static int ocGetNames_ELF ( ObjectCode* oc, int verb );
25 static int ocResolve_ELF ( ObjectCode* oc, int verb );
28 static char* hackyAppend ( char* s1, char* s2 );
31 /* --------------------------------------------------------------------------
32 * Arch-independent interface to the runtime linker
33 * ------------------------------------------------------------------------*/
35 ObjectCode* ocNew ( void (*errMsg)(char*),
36 void* (*clientLookup)(char*),
40 ObjectCode* oc = malloc(sizeof(ObjectCode));
42 errMsg("ocNew: can't allocate memory for object code record");
46 # if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
47 oc->formatName = "ELF";
50 errMsg("ocNew: not implemented on this platform");
54 oc->status = OBJECT_NOTINUSE;
55 oc->objFileName = objFileName;
56 oc->objFileSize = objFileSize;
58 oc->clientLookup = clientLookup;
60 oc->oImage = malloc ( objFileSize );
63 errMsg("ocNew: can't allocate memory for object code");
69 oc->sectionTab = NULL;
70 oc->sizesectionTab = 0;
71 oc->usedsectionTab = 0;
78 int ocLoadImage ( ObjectCode* oc, int verb )
82 assert (oc && oc->status==OBJECT_NOTINUSE);
83 if (verb) fprintf(stderr, "ocLoadImage %s\n", oc->objFileName );
84 f = fopen(oc->objFileName, "rb");
86 (oc->errMsg(hackyAppend("ocLoadImage: can't read: ",
90 n = fread ( oc->oImage, 1, oc->objFileSize, f );
91 if (n != oc->objFileSize) {
93 oc->errMsg(hackyAppend("ocLoadImage: I/O error whilst reading: ",
97 oc->status = OBJECT_OIMAGE;
98 if (verb) fprintf(stderr, "ocLoadImage %s: read %d bytes\n",
99 oc->objFileName, oc->objFileSize );
104 /* returns 1 if ok, 0 if error */
105 int ocVerifyImage ( ObjectCode* oc, int verb )
108 assert (oc && oc->status==OBJECT_OIMAGE);
109 if (verb) fprintf(stderr, "ocVerifyImage: begin\n");
110 # if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
111 ret = ocVerifyImage_ELF ( oc, verb );
113 oc->errMsg("ocVerifyImage: not implemented on this platform");
116 if (verb) fprintf(stderr, "ocVerifyImage: done, status = %d", ret);
118 if (ret) oc->status==OBJECT_VERIFIED;
123 /* returns 1 if ok, 0 if error */
124 int ocGetNames ( ObjectCode* oc, int verb )
127 assert (oc && oc->status==OBJECT_VERIFIED);
128 if (verb) fprintf(stderr, "ocGetNames: begin\n");
129 # if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
130 ret = ocGetNames_ELF ( oc, verb );
132 oc->errMsg("ocGetNames: not implemented on this platform");
135 if (verb) fprintf(stderr, "ocGetNames: done, status = %d\n", ret);
136 if (ret) oc->status==OBJECT_HAVENAMES;
141 /* returns 1 if ok, 0 if error */
142 int ocResolve ( ObjectCode* oc, int verb )
145 assert (oc && oc->status==OBJECT_HAVENAMES);
146 if (verb) fprintf(stderr, "ocResolve: begin\n");
147 # if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
148 ret = ocResolve_ELF ( oc, verb );
150 oc->errMsg("ocResolve: not implemented on this platform");
153 if (verb) fprintf(stderr, "ocResolve: done, status = %d\n", ret);
154 if (ret) oc->status==OBJECT_RESOLVED;
159 void ocFree ( ObjectCode* oc )
162 if (oc->oImage) free(oc->oImage);
163 if (oc->oTab) free(oc->oTab);
164 if (oc->sectionTab) free(oc->sectionTab);
170 /* --------------------------------------------------------------------------
171 * Simple, dynamically expandable association tables
172 * ------------------------------------------------------------------------*/
174 /* A bit tricky. Assumes that if tab==NULL, then
175 currUsed and *currSize must be zero.
176 Returns NULL if expansion failed.
178 static void* genericExpand ( void* tab,
179 int* currSize, int currUsed,
180 int initSize, int elemSize )
184 if (currUsed < *currSize) return tab;
185 size2 = (*currSize == 0) ? initSize : (2 * *currSize);
186 tab2 = malloc ( size2 * elemSize );
187 if (!tab2) return NULL;
189 memcpy ( tab2, tab, elemSize * *currSize );
191 if (tab) free ( tab );
196 /* returns 1 if success, 0 if error */
197 static int addSymbol ( ObjectCode* oc, char* nm, void* ad )
200 = genericExpand ( oc->oTab,
206 oc->errMsg("addSymbol: malloc failed whilst expanding table");
210 oc->oTab[ oc->usedoTab ].nm = nm;
211 oc->oTab[ oc->usedoTab ].ad = ad;
217 /* returns 1 if success, 0 if error */
218 static int addSection ( ObjectCode* oc, void* start, void* end, OSectionKind sect )
221 = genericExpand ( oc->sectionTab,
222 &(oc->sizesectionTab),
224 4, sizeof(OSection) );
226 oc->errMsg("addSection: malloc failed whilst expanding table");
229 oc->sectionTab = newTab;
230 oc->sectionTab[ oc->usedsectionTab ].start = start;
231 oc->sectionTab[ oc->usedsectionTab ].end = end;
232 oc->sectionTab[ oc->usedsectionTab ].kind = sect;
233 oc->usedsectionTab++;
238 void* ocLookupSym ( ObjectCode* oc, char* sym )
243 if (oc->status != OBJECT_HAVENAMES
244 && oc->status != OBJECT_RESOLVED) {
245 oc->errMsg("ocLookupSym: no symbols available");
249 for (i = 0; i < oc->usedoTab; i++) {
252 "ocLookupSym: request %s, table has %s\n",
253 sym, oc->oTab[i].nm );
254 if (0==strcmp(sym,oc->oTab[i].nm))
255 return oc->oTab[i].ad;
261 char* ocLookupAddr ( ObjectCode* oc, void* addr )
266 if (oc->status != OBJECT_HAVENAMES
267 && oc->status != OBJECT_RESOLVED) {
268 oc->errMsg("ocLookupAddr: no symbols available");
272 for (i = 0; i < oc->usedoTab; i++) {
273 if (addr == oc->oTab[i].ad)
274 return oc->oTab[i].nm;
280 OSectionKind ocLookupSection ( ObjectCode* oc, void* addr )
285 if (oc->status != OBJECT_HAVENAMES
286 && oc->status != OBJECT_RESOLVED) {
287 oc->errMsg("ocLookupSection: no symbols available");
288 return HUGS_SECTIONKIND_NOINFOAVAIL;
292 for (i = 0; i < oc->usedsectionTab; i++) {
293 if (oc->sectionTab[i].start <= addr
294 && addr <= oc->sectionTab[i].end)
295 return oc->sectionTab[i].kind;
298 return HUGS_SECTIONKIND_NOINFOAVAIL;
302 /* Ghastly append which leaks space. But we only use it for
303 error messages -- that's my excuse.
305 static char* hackyAppend ( char* s1, char* s2 )
307 char* res = malloc ( 4 + strlen(s1) + strlen(s2) );
309 fprintf ( stderr, "hugs: fatal: hackyAppend\n\t%s\n\t%s\n", s1, s2 );
317 /* --------------------------------------------------------------------------
319 * ------------------------------------------------------------------------*/
321 #if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
325 static char* findElfSection ( void* objImage, Elf32_Word sh_type )
328 char* ehdrC = (char*)objImage;
329 Elf32_Ehdr* ehdr = ( Elf32_Ehdr*)ehdrC;
330 Elf32_Shdr* shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
332 for (i = 0; i < ehdr->e_shnum; i++) {
333 if (shdr[i].sh_type == sh_type &&
334 i != ehdr->e_shstrndx) {
335 ptr = ehdrC + shdr[i].sh_offset;
343 static int ocVerifyImage_ELF ( ObjectCode* oc, int verb )
347 int i, j, nent, nstrtab, nsymtabs;
351 char* ehdrC = (char*)(oc->oImage);
352 Elf32_Ehdr* ehdr = ( Elf32_Ehdr*)ehdrC;
354 if (ehdr->e_ident[EI_MAG0] != ELFMAG0 ||
355 ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
356 ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
357 ehdr->e_ident[EI_MAG3] != ELFMAG3) {
358 oc->errMsg("Not an ELF header");
361 if (verb) fprintf ( stderr, "Is an ELF header\n" );
363 if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) {
364 oc->errMsg("Not 32 bit ELF" );
367 if (verb) fprintf ( stderr, "Is 32 bit ELF\n" );
369 if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) {
370 if (verb) fprintf ( stderr, "Is little-endian\n" );
372 if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) {
373 if (verb) fprintf ( stderr, "Is big-endian\n" );
375 oc->errMsg("Unknown endiannness");
379 if (ehdr->e_type != ET_REL) {
380 oc->errMsg("Not a relocatable object (.o) file");
383 if (verb) fprintf ( stderr, "Is a relocatable object (.o) file\n" );
385 if (verb) fprintf ( stderr, "Architecture is " );
386 switch (ehdr->e_machine) {
387 case EM_386: if (verb) fprintf ( stderr, "x86\n" ); break;
388 case EM_SPARC: if (verb) fprintf ( stderr, "sparc\n" ); break;
389 default: if (verb) fprintf ( stderr, "unknown\n" );
390 oc->errMsg("Unknown architecture");
396 "\nSection header table: start %d, n_entries %d, ent_size %d\n",
397 ehdr->e_shoff, ehdr->e_shnum, ehdr->e_shentsize );
399 assert (ehdr->e_shentsize == sizeof(Elf32_Shdr));
401 shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
403 if (ehdr->e_shstrndx == SHN_UNDEF) {
404 oc->errMsg("No section header string table");
407 if (verb) fprintf ( stderr,"Section header string table is section %d\n",
409 sh_strtab = ehdrC + shdr[ehdr->e_shstrndx].sh_offset;
412 for (i = 0; i < ehdr->e_shnum; i++) {
413 if (verb) fprintf ( stderr, "%2d: ", i );
414 if (verb) fprintf ( stderr, "type=%2d ", shdr[i].sh_type );
415 if (verb) fprintf ( stderr, "size=%4d ", shdr[i].sh_size );
416 if (verb) fprintf ( stderr, "offs=%4d ", shdr[i].sh_offset );
417 if (verb) fprintf ( stderr, " (%p .. %p) ",
418 ehdrC + shdr[i].sh_offset,
419 ehdrC + shdr[i].sh_offset + shdr[i].sh_size - 1);
421 if (shdr[i].sh_type == SHT_REL && verb) fprintf ( stderr, "Rel " ); else
422 if (shdr[i].sh_type == SHT_RELA && verb) fprintf ( stderr, "RelA " ); else
423 if (verb) fprintf ( stderr, " " );
424 if (sh_strtab && verb)
425 fprintf ( stderr, "sname=%s", sh_strtab + shdr[i].sh_name );
426 if (verb) fprintf ( stderr, "\n" );
429 if (verb) fprintf ( stderr, "\n\nString tables\n" );
432 for (i = 0; i < ehdr->e_shnum; i++) {
433 if (shdr[i].sh_type == SHT_STRTAB &&
434 i != ehdr->e_shstrndx) {
436 fprintf ( stderr, " section %d is a normal string table\n", i );
437 strtab = ehdrC + shdr[i].sh_offset;
442 oc->errMsg("WARNING: no string tables, or too many");
447 if (verb) fprintf ( stderr, "\n\nSymbol tables\n" );
448 for (i = 0; i < ehdr->e_shnum; i++) {
449 if (shdr[i].sh_type != SHT_SYMTAB) continue;
450 if (verb) fprintf ( stderr, "section %d is a symbol table\n", i );
452 stab = (Elf32_Sym*) (ehdrC + shdr[i].sh_offset);
453 nent = shdr[i].sh_size / sizeof(Elf32_Sym);
454 if (verb) fprintf ( stderr, " number of entries is apparently %d (%d rem)\n",
456 shdr[i].sh_size % sizeof(Elf32_Sym)
458 if (0 != shdr[i].sh_size % sizeof(Elf32_Sym)) {
459 oc->errMsg("non-integral number of symbol table entries");
462 for (j = 0; j < nent; j++) {
463 if (verb) fprintf ( stderr, " %2d ", j );
464 if (verb) fprintf ( stderr, " sec=%-5d size=%-3d val=%-5p ",
465 (int)stab[j].st_shndx,
466 (int)stab[j].st_size,
467 (char*)stab[j].st_value );
469 if (verb) fprintf ( stderr, "type=" );
470 switch (ELF32_ST_TYPE(stab[j].st_info)) {
471 case STT_NOTYPE: if (verb) fprintf ( stderr, "notype " ); break;
472 case STT_OBJECT: if (verb) fprintf ( stderr, "object " ); break;
473 case STT_FUNC : if (verb) fprintf ( stderr, "func " ); break;
474 case STT_SECTION: if (verb) fprintf ( stderr, "section" ); break;
475 case STT_FILE: if (verb) fprintf ( stderr, "file " ); break;
476 default: if (verb) fprintf ( stderr, "? " ); break;
478 if (verb) fprintf ( stderr, " " );
480 if (verb) fprintf ( stderr, "bind=" );
481 switch (ELF32_ST_BIND(stab[j].st_info)) {
482 case STB_LOCAL : if (verb) fprintf ( stderr, "local " ); break;
483 case STB_GLOBAL: if (verb) fprintf ( stderr, "global" ); break;
484 case STB_WEAK : if (verb) fprintf ( stderr, "weak " ); break;
485 default: if (verb) fprintf ( stderr, "? " ); break;
487 if (verb) fprintf ( stderr, " " );
489 if (verb) fprintf ( stderr, "name=%s\n", strtab + stab[j].st_name );
494 oc->errMsg("Didn't find any symbol tables");
502 static int ocGetNames_ELF ( ObjectCode* oc, int verb )
507 char* ehdrC = (char*)(oc->oImage);
508 Elf32_Ehdr* ehdr = (Elf32_Ehdr*)ehdrC;
509 char* strtab = findElfSection ( ehdrC, SHT_STRTAB );
510 Elf32_Shdr* shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
511 char* sh_strtab = ehdrC + shdr[ehdr->e_shstrndx].sh_offset;
514 oc->errMsg("no strtab!");
519 for (i = 0; i < ehdr->e_shnum; i++) {
521 /* make a HugsDLSection entry for relevant sections */
522 DLSect kind = HUGS_DL_SECTION_OTHER;
523 if (0==strcmp(".data",sh_strtab+shdr[i].sh_name) ||
524 0==strcmp(".data1",sh_strtab+shdr[i].sh_name))
525 kind = HUGS_DL_SECTION_RWDATA;
526 if (0==strcmp(".text",sh_strtab+shdr[i].sh_name) ||
527 0==strcmp(".rodata",sh_strtab+shdr[i].sh_name) ||
528 0==strcmp(".rodata1",sh_strtab+shdr[i].sh_name))
529 kind = HUGS_DL_SECTION_CODE_OR_RODATA;
530 if (kind != HUGS_DL_SECTION_OTHER)
533 ehdrC + shdr[i].sh_offset,
534 ehdrC + shdr[i].sh_offset + shdr[i].sh_size - 1,
538 if (shdr[i].sh_type != SHT_SYMTAB) continue;
540 /* copy stuff into this module's object symbol table */
541 stab = (Elf32_Sym*) (ehdrC + shdr[i].sh_offset);
542 nent = shdr[i].sh_size / sizeof(Elf32_Sym);
543 for (j = 0; j < nent; j++) {
544 if ( ( ELF32_ST_BIND(stab[j].st_info)==STB_GLOBAL ||
545 ELF32_ST_BIND(stab[j].st_info)==STB_LOCAL
548 ( ELF32_ST_TYPE(stab[j].st_info)==STT_FUNC ||
549 ELF32_ST_TYPE(stab[j].st_info)==STT_OBJECT ||
550 ELF32_ST_TYPE(stab[j].st_info)==STT_NOTYPE)
552 char* nm = strtab + stab[j].st_name;
554 + shdr[ stab[j].st_shndx ].sh_offset
559 fprintf(stderr, "addOTabName: %10p %s %s\n",
560 ad, textToStr(module(m).text), nm );
561 addSymbol ( oc, nm, ad );
563 //else fprintf(stderr, "skipping `%s'\n", strtab + stab[j].st_name );
570 static int ocResolve_ELF ( ObjectCode* oc, int verb )
572 char symbol[1000]; // ToDo
575 Elf32_Sym* stab = NULL;
576 char* ehdrC = (char*)(oc->oImage);
577 Elf32_Ehdr* ehdr = (Elf32_Ehdr*) ehdrC;
578 Elf32_Shdr* shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
581 /* first find "the" symbol table */
582 stab = (Elf32_Sym*) findElfSection ( ehdrC, SHT_SYMTAB );
584 /* also go find the string table */
585 strtab = findElfSection ( ehdrC, SHT_STRTAB );
587 if (!stab || !strtab) {
588 oc->errMsg("can't find string or symbol table");
592 for (i = 0; i < ehdr->e_shnum; i++) {
593 if (shdr[i].sh_type == SHT_REL ) {
594 Elf32_Rel* rtab = (Elf32_Rel*) (ehdrC + shdr[i].sh_offset);
595 Int nent = shdr[i].sh_size / sizeof(Elf32_Rel);
596 Int target_shndx = shdr[i].sh_info;
597 Int symtab_shndx = shdr[i].sh_link;
598 stab = (Elf32_Sym*) (ehdrC + shdr[ symtab_shndx ].sh_offset);
599 targ = (Elf32_Word*)(ehdrC + shdr[ target_shndx ].sh_offset);
602 "relocations for section %d using symtab %d\n",
603 target_shndx, symtab_shndx );
604 for (j = 0; j < nent; j++) {
605 Elf32_Addr offset = rtab[j].r_offset;
606 Elf32_Word info = rtab[j].r_info;
608 Elf32_Addr P = ((Elf32_Addr)targ) + offset;
609 Elf32_Word* pP = (Elf32_Word*)P;
613 if (verb) fprintf ( stderr, "Rel entry %3d is raw(%6p %6p) ",
614 j, (void*)offset, (void*)info );
616 if (verb) fprintf ( stderr, " ZERO\n" );
619 /* First see if it is a nameless local symbol. */
620 if (stab[ ELF32_R_SYM(info)].st_name == 0) {
621 if (verb) fprintf ( stderr, "(noname) ");
622 S = (Elf32_Addr)(ehdrC
623 + shdr[stab[ELF32_R_SYM(info)].st_shndx ].sh_offset
624 + stab[ELF32_R_SYM(info)].st_value
626 strcpy ( symbol, "(noname)");
628 /* No? Perhaps it's a named symbol in this file. */
629 strcpy ( symbol, strtab+stab[ ELF32_R_SYM(info)].st_name );
630 if (verb) fprintf ( stderr, "`%s' ", symbol );
631 S = (Elf32_Addr)lookupSymbol ( oc, symbol );
633 /* No? Ok, too hard. Hand the problem to the client.
634 And if that fails, we're outta options.
636 S = (Elf32_Addr)(oc->clientLookup ( symbol ) );
639 if (verb) fprintf ( stderr, "resolves to %p\n", (void*)S );
642 strcpy(errtxt,oc->objFileName);
643 strcat(errtxt,": unresolvable reference to: ");
644 strcat(errtxt,symbol);
649 /* fprintf ( stderr, "Reloc: P = %p S = %p A = %p\n\n",
650 (void*)P, (void*)S, (void*)A );
652 switch (ELF32_R_TYPE(info)) {
653 case R_386_32: *pP = S + A; break;
654 case R_386_PC32: *pP = S + A - P; break;
655 default: fprintf(stderr,
656 "unhandled ELF relocation type %d\n",
658 oc->errMsg("unhandled ELF relocation type");
665 if (shdr[i].sh_type == SHT_RELA) {
666 oc->errMsg("RelA style reloc table -- not yet done");
675 #endif /* defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS) */
679 /*-------------------------------------------------------------------------*/