[project @ 2000-02-25 17:35:11 by sewardj]
[ghc-hetmet.git] / ghc / interpreter / object.c
1
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.
6  *
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.
12  *
13  * ------------------------------------------------------------------------*/
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <assert.h>
19 #include "config.h"                             /* for linux_TARGET_OS etc */
20 #include "object.h"
21
22
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 );
27 #endif
28
29 static char* hackyAppend ( char* s1, char* s2 );
30 static int   sortSymbols ( ObjectCode* oc );
31
32
33 /* --------------------------------------------------------------------------
34  * Arch-independent interface to the runtime linker
35  * ------------------------------------------------------------------------*/
36
37 ObjectCode*  ocNew ( void  (*errMsg)(char*),
38                      void* (*clientLookup)(char*),
39                      char*  objFileName,
40                      int    objFileSize )
41 {
42    ObjectCode* oc     = malloc(sizeof(ObjectCode));
43    if (!oc) {
44       errMsg("ocNew: can't allocate memory for object code record");
45       return NULL;
46    }
47
48 #  if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
49    oc->formatName = "ELF";
50 #  else
51    free(oc);
52    errMsg("ocNew: not implemented on this platform");
53    return NULL;
54 #  endif
55
56    oc->status         = OBJECT_NOTINUSE;
57    oc->objFileName    = objFileName;
58    oc->objFileSize    = objFileSize;
59    oc->errMsg         = errMsg;
60    oc->clientLookup   = clientLookup;
61
62    oc->oImage         = malloc ( objFileSize );
63    if (!oc->oImage) {
64       free(oc);
65       errMsg("ocNew: can't allocate memory for object code");
66       return NULL;
67    }
68    oc->oTab           = NULL;
69    oc->sizeoTab       = 0;
70    oc->usedoTab       = 0;
71    oc->sectionTab     = NULL;
72    oc->sizesectionTab = 0;
73    oc->usedsectionTab = 0;
74    oc->next           = NULL;
75
76    return oc;
77 }
78                             
79
80 int ocLoadImage ( ObjectCode* oc, int verb )
81 {
82    int   n;
83    FILE* f;
84    assert (oc && oc->status==OBJECT_NOTINUSE);
85    if (verb) fprintf(stderr, "ocLoadImage %s\n", oc->objFileName );
86    f = fopen(oc->objFileName, "rb");
87    if (!f) {
88        (oc->errMsg(hackyAppend("ocLoadImage: can't read: ",
89                                oc->objFileName)));
90        return 0;
91    }
92    n = fread ( oc->oImage, 1, oc->objFileSize, f );
93    if (n != oc->objFileSize) {
94       fclose(f);
95       oc->errMsg(hackyAppend("ocLoadImage: I/O error whilst reading: ",
96                              oc->objFileName));
97       return 0;
98    }
99    oc->status = OBJECT_OIMAGE;
100    if (verb) fprintf(stderr, "ocLoadImage %s: read %d bytes\n", 
101                      oc->objFileName, oc->objFileSize );
102    return 1;
103 }
104
105
106 /* returns 1 if ok, 0 if error */
107 int ocVerifyImage ( ObjectCode* oc, int verb )
108 {
109    int ret;
110    assert (oc && oc->status==OBJECT_OIMAGE);
111    if (verb) fprintf(stderr, "ocVerifyImage: begin\n");
112 #  if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
113    ret = ocVerifyImage_ELF ( oc, verb );
114 #  else
115    oc->errMsg("ocVerifyImage: not implemented on this platform");
116    return 0;
117 #  endif
118    if (verb) fprintf(stderr, "ocVerifyImage: done, status = %d", ret);
119
120    if (ret) oc->status = OBJECT_VERIFIED;
121    return ret;
122 }
123
124
125 /* returns 1 if ok, 0 if error */
126 int ocGetNames ( ObjectCode* oc, int verb )
127 {
128    int ret;
129    assert (oc && oc->status==OBJECT_VERIFIED);
130    if (verb) fprintf(stderr, "ocGetNames: begin\n");
131 #  if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
132    ret = ocGetNames_ELF ( oc, verb );
133 #  else
134    oc->errMsg("ocGetNames: not implemented on this platform");
135    return 0;
136 #  endif
137    if (verb) fprintf(stderr, "ocGetNames: done, status = %d\n", ret);
138    if (ret) ret = sortSymbols(oc);
139    if (ret) oc->status = OBJECT_HAVENAMES;
140    return ret;
141 }
142
143
144 /* returns 1 if ok, 0 if error */
145 int ocResolve ( ObjectCode* oc, int verb )
146 {
147    int ret;
148    assert (oc && oc->status==OBJECT_HAVENAMES);
149    if (verb) fprintf(stderr, "ocResolve: begin\n");
150 #  if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
151    ret = ocResolve_ELF ( oc, verb );
152 #  else
153    oc->errMsg("ocResolve: not implemented on this platform");
154    return 0;
155 #  endif
156    if (verb) fprintf(stderr, "ocResolve: done, status = %d\n", ret);
157    if (ret) oc->status = OBJECT_RESOLVED;
158    return ret;
159 }
160
161
162 void ocFree ( ObjectCode* oc )
163 {
164    if (oc) {
165       if (oc->oImage)     free(oc->oImage);
166       if (oc->oTab)       free(oc->oTab);
167       if (oc->sectionTab) free(oc->sectionTab);
168       free(oc);
169    }
170 }
171
172
173 /* --------------------------------------------------------------------------
174  * Simple, dynamically expandable association tables
175  * ------------------------------------------------------------------------*/
176
177 /* A bit tricky.  Assumes that if tab==NULL, then 
178    currUsed and *currSize must be zero.
179    Returns NULL if expansion failed.
180 */
181 static void* genericExpand ( void* tab, 
182                              int*  currSize, int  currUsed,
183                              int   initSize, int  elemSize )
184 {
185    int   size2;
186    void* tab2;
187    if (currUsed < *currSize) return tab;
188    size2 = (*currSize == 0) ? initSize : (2 * *currSize);
189    tab2 = malloc ( size2 * elemSize );
190    if (!tab2) return NULL;
191    if (*currSize > 0)
192       memcpy ( tab2, tab, elemSize * *currSize );
193    *currSize = size2;
194    if (tab) free ( tab );
195    return tab2;
196 }
197
198
199 /* returns 1 if success, 0 if error */
200 static int addSymbol ( ObjectCode* oc, char* nm, void* ad )
201 {
202    OSym* newTab
203       = genericExpand ( oc->oTab, 
204                         &(oc->sizeoTab),
205                         oc->usedoTab,
206                         8, sizeof(OSym) );
207
208    if (!newTab) {
209       oc->errMsg("addSymbol: malloc failed whilst expanding table");
210       return 0;
211    }
212    oc->oTab = newTab;
213    oc->oTab[ oc->usedoTab ].nm = nm;
214    oc->oTab[ oc->usedoTab ].ad = ad;
215    oc->usedoTab++;
216    return 1;
217 }
218
219
220 /* Reorder symbol table so that symbols are in alphabetical order.
221    Detects an error if, after sorting, any two symbols are the same,
222    since this would imply that the same symbol has been inserted more 
223    than once.  Returns 1 if success, 0 if error.
224 */
225 static int sortSymbols ( ObjectCode* oc )
226 {
227    static int incs[14] 
228       = { 1, 4, 13, 40, 121, 364, 1093, 3280,
229           9841, 29524, 88573, 265720, 797161, 2391484 };
230
231    int lo = 0;
232    int hi = oc->usedoTab-1;
233    int i, j, h, bigN, hp;
234    OSym v;
235
236    bigN = hi - lo + 1; if (bigN < 2) return 1;
237    hp = 0; while (incs[hp] < bigN) hp++; hp--;
238
239    for (; hp >= 0; hp--) {
240       h = incs[hp];
241       i = lo + h;
242       while (1) {
243          if (i > hi) break;
244          v = oc->oTab[i];
245          j = i;
246          while (strcmp(oc->oTab[j-h].nm, v.nm) > 0) {
247             oc->oTab[j] = oc->oTab[j-h];
248             j = j - h;
249             if (j <= (lo + h - 1)) break;
250          }
251          oc->oTab[j] = v;
252          i++;
253       }
254    }
255
256    for (i = 1; i < oc->usedoTab; i++) {
257       j = strcmp(oc->oTab[i-1].nm, oc->oTab[i].nm);
258       if (j  > 0) { 
259          oc->errMsg("sortSymbols: sorting failed"); 
260          return 0;
261       }
262       if (j == 0) {
263          oc->errMsg("sortSymbols: duplicate symbols in object file");
264          return 0;
265       }
266    }
267
268    return 1;
269 }
270
271
272 /* returns 1 if success, 0 if error */
273 static int addSection ( ObjectCode* oc, void* start, void* end, OSectionKind sect )
274 {
275    OSection* newTab
276       = genericExpand ( oc->sectionTab,
277                         &(oc->sizesectionTab),
278                         oc->usedsectionTab,
279                         4, sizeof(OSection) );
280    if (!newTab) {
281       oc->errMsg("addSection: malloc failed whilst expanding table");
282       return 0;
283    }
284    oc->sectionTab = newTab;
285    oc->sectionTab[ oc->usedsectionTab ].start = start;
286    oc->sectionTab[ oc->usedsectionTab ].end   = end;
287    oc->sectionTab[ oc->usedsectionTab ].kind  = sect;
288    oc->usedsectionTab++;
289    return 1;
290 }
291
292
293 void* ocLookupSym ( ObjectCode* oc, char* sym )
294 {
295    int lo, hi, mid, cmp;
296
297    assert(oc);
298    if (oc->status != OBJECT_HAVENAMES 
299        && oc->status != OBJECT_RESOLVED) {
300       oc->errMsg("ocLookupSym: no symbols available");
301       return NULL;
302    }
303
304    /* Originally used a sequential search; should still work
305    for (i = 0; i < oc->usedoTab; i++) {
306       if (0)
307          fprintf ( stderr, 
308                    "ocLookupSym: request %s, table has %s\n",
309                    sym, oc->oTab[i].nm );
310       if (0==strcmp(sym,oc->oTab[i].nm))
311          return oc->oTab[i].ad;
312    }
313    */
314
315    lo = 0; 
316    hi = oc->usedoTab-1;
317    while (1) {
318       /* Invariant: the unsearched area is oc->oTab[lo .. hi] inclusive. */
319       if (hi < lo) return NULL;
320       mid = (hi + lo) / 2;
321       cmp = strcmp(sym, oc->oTab[mid].nm);
322       if (cmp == 0) return oc->oTab[mid].ad;
323       if (cmp < 0) hi = mid-1;
324       if (cmp > 0) lo = mid+1;
325    }
326 }
327
328
329 char* ocLookupAddr ( ObjectCode* oc, void* addr )
330 {
331    int i;
332
333    assert(oc);
334    if (oc->status != OBJECT_HAVENAMES 
335        && oc->status != OBJECT_RESOLVED) {
336       oc->errMsg("ocLookupAddr: no symbols available");
337       return NULL;
338    }
339
340    for (i = 0; i < oc->usedoTab; i++) {
341       if (addr == oc->oTab[i].ad)
342          return oc->oTab[i].nm;
343    }
344    return NULL;
345 }
346
347
348 OSectionKind ocLookupSection ( ObjectCode* oc, void* addr )
349 {
350    int i;
351
352    assert(oc);
353    if (oc->status != OBJECT_HAVENAMES 
354        && oc->status != OBJECT_RESOLVED) {
355       oc->errMsg("ocLookupSection: no symbols available");
356       return HUGS_SECTIONKIND_NOINFOAVAIL;
357    }
358
359
360    for (i = 0; i < oc->usedsectionTab; i++) {
361       if (oc->sectionTab[i].start <= addr 
362           && addr <= oc->sectionTab[i].end)
363          return oc->sectionTab[i].kind;
364    }
365
366    return HUGS_SECTIONKIND_NOINFOAVAIL;
367 }
368
369
370 /* Ghastly append which leaks space.  But we only use it for
371    error messages -- that's my excuse.
372 */
373 static char* hackyAppend ( char* s1, char* s2 )
374 {
375    char* res = malloc ( 4 + strlen(s1) + strlen(s2) );
376    if (!res) {
377       fprintf ( stderr, "hugs: fatal: hackyAppend\n\t%s\n\t%s\n", s1, s2 );
378       assert(res);
379    }
380    strcpy(res,s1);
381    strcat(res,s2);
382    return res;
383 }
384
385 /* --------------------------------------------------------------------------
386  * ELF specifics
387  * ------------------------------------------------------------------------*/
388
389 #define FALSE 0
390 #define TRUE  1
391
392 #if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
393
394 #include <elf.h>
395
396 static char* findElfSection ( void* objImage, Elf32_Word sh_type )
397 {
398    int i;
399    char* ehdrC = (char*)objImage;
400    Elf32_Ehdr* ehdr = ( Elf32_Ehdr*)ehdrC;
401    Elf32_Shdr* shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
402    char* ptr = NULL;
403    for (i = 0; i < ehdr->e_shnum; i++) {
404       if (shdr[i].sh_type == sh_type &&
405           i !=  ehdr->e_shstrndx) {
406          ptr = ehdrC + shdr[i].sh_offset;
407          break;
408       }
409    }
410    return ptr;
411 }
412
413
414 static int ocVerifyImage_ELF ( ObjectCode* oc, int verb )
415 {
416    Elf32_Shdr* shdr;
417    Elf32_Sym*  stab;
418    int i, j, nent, nstrtab, nsymtabs;
419    char* sh_strtab;
420    char* strtab;
421
422    char*       ehdrC = (char*)(oc->oImage);
423    Elf32_Ehdr* ehdr  = ( Elf32_Ehdr*)ehdrC;
424
425    if (ehdr->e_ident[EI_MAG0] != ELFMAG0 ||
426        ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
427        ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
428        ehdr->e_ident[EI_MAG3] != ELFMAG3) {
429       oc->errMsg("Not an ELF header");
430       return FALSE;
431    }
432    if (verb) fprintf ( stderr, "Is an ELF header\n" );
433
434    if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) {
435       oc->errMsg("Not 32 bit ELF" );
436       return FALSE;
437    }
438    if (verb) fprintf ( stderr, "Is 32 bit ELF\n" );
439
440    if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) {
441       if (verb) fprintf ( stderr, "Is little-endian\n" );
442    } else
443    if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) {
444       if (verb) fprintf ( stderr, "Is big-endian\n" );
445    } else {
446       oc->errMsg("Unknown endiannness");
447       return FALSE;
448    }
449
450    if (ehdr->e_type != ET_REL) {
451       oc->errMsg("Not a relocatable object (.o) file");
452       return FALSE;
453    }
454    if (verb) fprintf ( stderr, "Is a relocatable object (.o) file\n" );
455
456    if (verb) fprintf ( stderr, "Architecture is " );
457    switch (ehdr->e_machine) {
458       case EM_386:   if (verb) fprintf ( stderr, "x86\n" ); break;
459       case EM_SPARC: if (verb) fprintf ( stderr, "sparc\n" ); break;
460       default:       if (verb) fprintf ( stderr, "unknown\n" ); 
461                      oc->errMsg("Unknown architecture");
462                      return FALSE;
463    }
464
465    if (verb) 
466    fprintf ( stderr,
467              "\nSection header table: start %d, n_entries %d, ent_size %d\n", 
468              ehdr->e_shoff, ehdr->e_shnum, ehdr->e_shentsize  );
469
470    assert (ehdr->e_shentsize == sizeof(Elf32_Shdr));
471
472    shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
473
474    if (ehdr->e_shstrndx == SHN_UNDEF) {
475       oc->errMsg("No section header string table");
476       return FALSE;
477    } else {
478       if (verb) fprintf (  stderr,"Section header string table is section %d\n", 
479                           ehdr->e_shstrndx);
480       sh_strtab = ehdrC + shdr[ehdr->e_shstrndx].sh_offset;
481    }
482
483    for (i = 0; i < ehdr->e_shnum; i++) {
484       if (verb) fprintf ( stderr, "%2d:  ", i );
485       if (verb) fprintf ( stderr, "type=%2d  ", shdr[i].sh_type );
486       if (verb) fprintf ( stderr, "size=%4d  ", shdr[i].sh_size );
487       if (verb) fprintf ( stderr, "offs=%4d  ", shdr[i].sh_offset );
488       if (verb) fprintf ( stderr, "  (%p .. %p)  ",
489                ehdrC + shdr[i].sh_offset, 
490                ehdrC + shdr[i].sh_offset + shdr[i].sh_size - 1);
491
492       if (shdr[i].sh_type == SHT_REL  && verb) fprintf ( stderr, "Rel  " ); else
493       if (shdr[i].sh_type == SHT_RELA && verb) fprintf ( stderr, "RelA " ); else
494       if (verb)                                fprintf ( stderr, "     " );
495       if (sh_strtab && verb) 
496          fprintf ( stderr, "sname=%s", sh_strtab + shdr[i].sh_name );
497       if (verb) fprintf ( stderr, "\n" );
498    }
499
500    if (verb) fprintf ( stderr, "\n\nString tables\n" );
501    strtab = NULL;
502    nstrtab = 0;
503    for (i = 0; i < ehdr->e_shnum; i++) {
504       if (shdr[i].sh_type == SHT_STRTAB &&
505           i !=  ehdr->e_shstrndx) {
506          if (verb) 
507             fprintf ( stderr, "   section %d is a normal string table\n", i );
508          strtab = ehdrC + shdr[i].sh_offset;
509          nstrtab++;
510       }
511    }  
512    if (nstrtab != 1) {
513       oc->errMsg("WARNING: no string tables, or too many");
514       return FALSE;
515    }
516
517    nsymtabs = 0;
518    if (verb) fprintf ( stderr, "\n\nSymbol tables\n" ); 
519    for (i = 0; i < ehdr->e_shnum; i++) {
520       if (shdr[i].sh_type != SHT_SYMTAB) continue;
521       if (verb) fprintf ( stderr, "section %d is a symbol table\n", i );
522       nsymtabs++;
523       stab = (Elf32_Sym*) (ehdrC + shdr[i].sh_offset);
524       nent = shdr[i].sh_size / sizeof(Elf32_Sym);
525       if (verb) fprintf ( stderr, "   number of entries is apparently %d (%d rem)\n",
526                nent,
527                shdr[i].sh_size % sizeof(Elf32_Sym)
528              );
529       if (0 != shdr[i].sh_size % sizeof(Elf32_Sym)) {
530          oc->errMsg("non-integral number of symbol table entries");
531          return FALSE;
532       }
533       for (j = 0; j < nent; j++) {
534          if (verb) fprintf ( stderr, "   %2d  ", j );
535          if (verb) fprintf ( stderr, "  sec=%-5d  size=%-3d  val=%-5p  ", 
536                              (int)stab[j].st_shndx,
537                              (int)stab[j].st_size,
538                              (char*)stab[j].st_value );
539
540          if (verb) fprintf ( stderr, "type=" );
541          switch (ELF32_ST_TYPE(stab[j].st_info)) {
542             case STT_NOTYPE:  if (verb) fprintf ( stderr, "notype " ); break;
543             case STT_OBJECT:  if (verb) fprintf ( stderr, "object " ); break;
544             case STT_FUNC  :  if (verb) fprintf ( stderr, "func   " ); break;
545             case STT_SECTION: if (verb) fprintf ( stderr, "section" ); break;
546             case STT_FILE:    if (verb) fprintf ( stderr, "file   " ); break;
547             default:          if (verb) fprintf ( stderr, "?      " ); break;
548          }
549          if (verb) fprintf ( stderr, "  " );
550
551          if (verb) fprintf ( stderr, "bind=" );
552          switch (ELF32_ST_BIND(stab[j].st_info)) {
553             case STB_LOCAL :  if (verb) fprintf ( stderr, "local " ); break;
554             case STB_GLOBAL:  if (verb) fprintf ( stderr, "global" ); break;
555             case STB_WEAK  :  if (verb) fprintf ( stderr, "weak  " ); break;
556             default:          if (verb) fprintf ( stderr, "?     " ); break;
557          }
558          if (verb) fprintf ( stderr, "  " );
559
560          if (verb) fprintf ( stderr, "name=%s\n", strtab + stab[j].st_name );
561       }
562    }
563
564    if (nsymtabs == 0) {
565       oc->errMsg("Didn't find any symbol tables");
566       return FALSE;
567    }
568
569    return TRUE;
570 }
571
572
573 static int ocGetNames_ELF ( ObjectCode* oc, int verb )
574 {
575    int i, j, k, nent;
576    Elf32_Sym* stab;
577
578    char*       ehdrC      = (char*)(oc->oImage);
579    Elf32_Ehdr* ehdr       = (Elf32_Ehdr*)ehdrC;
580    char*       strtab     = findElfSection ( ehdrC, SHT_STRTAB );
581    Elf32_Shdr* shdr       = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
582    char*       sh_strtab  = ehdrC + shdr[ehdr->e_shstrndx].sh_offset;
583
584    if (!strtab) {
585       oc->errMsg("no strtab!");
586       return FALSE;
587    }
588
589    k = 0;
590    for (i = 0; i < ehdr->e_shnum; i++) {
591
592       /* make a HugsDLSection entry for relevant sections */
593       OSectionKind kind = HUGS_SECTIONKIND_OTHER;
594       if (0==strcmp(".data",sh_strtab+shdr[i].sh_name) ||
595           0==strcmp(".data1",sh_strtab+shdr[i].sh_name))
596          kind = HUGS_SECTIONKIND_RWDATA;
597       if (0==strcmp(".text",sh_strtab+shdr[i].sh_name) ||
598           0==strcmp(".rodata",sh_strtab+shdr[i].sh_name) ||
599           0==strcmp(".rodata1",sh_strtab+shdr[i].sh_name))
600          kind = HUGS_SECTIONKIND_CODE_OR_RODATA;
601       if (kind != HUGS_SECTIONKIND_OTHER)
602          addSection (
603             oc,
604             ehdrC + shdr[i].sh_offset, 
605             ehdrC + shdr[i].sh_offset + shdr[i].sh_size - 1,
606             kind
607          );
608
609       if (shdr[i].sh_type != SHT_SYMTAB) continue;
610
611       /* copy stuff into this module's object symbol table */
612       stab = (Elf32_Sym*) (ehdrC + shdr[i].sh_offset);
613       nent = shdr[i].sh_size / sizeof(Elf32_Sym);
614       for (j = 0; j < nent; j++) {
615          if ( ( ELF32_ST_BIND(stab[j].st_info)==STB_GLOBAL ||
616                 ELF32_ST_BIND(stab[j].st_info)==STB_LOCAL
617               )
618               &&
619               ( ELF32_ST_TYPE(stab[j].st_info)==STT_FUNC ||
620                 ELF32_ST_TYPE(stab[j].st_info)==STT_OBJECT)
621               /* || ELF32_ST_TYPE(stab[j].st_info)==STT_NOTYPE */
622               ) {
623             char* nm = strtab + stab[j].st_name;
624             char* ad = ehdrC 
625                        + shdr[ stab[j].st_shndx ].sh_offset
626                        + stab[j].st_value;
627             assert(nm);
628             assert(ad);
629             if (verb)
630                fprintf(stderr, "addOTabName: %10p  %s %s\n",
631                        ad, oc->objFileName, nm );
632             if (!addSymbol ( oc, nm, ad )) return FALSE;
633          }
634 #if 0
635          else fprintf(stderr, "skipping `%s'\n", strtab + stab[j].st_name );
636 #endif
637       }
638    }
639
640    return TRUE;
641 }
642
643
644 static int ocResolve_ELF ( ObjectCode* oc, int verb )
645 {
646    char symbol[1000]; // ToDo
647    char* strtab;
648    int   i, j;
649    Elf32_Sym*  stab = NULL;
650    char*       ehdrC = (char*)(oc->oImage);
651    Elf32_Ehdr* ehdr = (Elf32_Ehdr*) ehdrC;
652    Elf32_Shdr* shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
653    Elf32_Word* targ;
654
655    /* first find "the" symbol table */
656    stab = (Elf32_Sym*) findElfSection ( ehdrC, SHT_SYMTAB );
657
658    /* also go find the string table */
659    strtab = findElfSection ( ehdrC, SHT_STRTAB );
660
661    if (!stab || !strtab) {
662       oc->errMsg("can't find string or symbol table");
663       return FALSE; 
664    }
665
666    for (i = 0; i < ehdr->e_shnum; i++) {
667       if (shdr[i].sh_type == SHT_REL ) {
668          Elf32_Rel*  rtab = (Elf32_Rel*) (ehdrC + shdr[i].sh_offset);
669          int         nent = shdr[i].sh_size / sizeof(Elf32_Rel);
670          int target_shndx = shdr[i].sh_info;
671          int symtab_shndx = shdr[i].sh_link;
672          stab  = (Elf32_Sym*) (ehdrC + shdr[ symtab_shndx ].sh_offset);
673          targ  = (Elf32_Word*)(ehdrC + shdr[ target_shndx ].sh_offset);
674          if (verb)
675          fprintf ( stderr,
676                   "relocations for section %d using symtab %d\n",
677                   target_shndx, symtab_shndx );
678          for (j = 0; j < nent; j++) {
679             Elf32_Addr offset = rtab[j].r_offset;
680             Elf32_Word info   = rtab[j].r_info;
681
682             Elf32_Addr  P = ((Elf32_Addr)targ) + offset;
683             Elf32_Word* pP = (Elf32_Word*)P;
684             Elf32_Addr  A = *pP;
685             Elf32_Addr  S;
686
687             if (verb) fprintf ( stderr, "Rel entry %3d is raw(%6p %6p)   ", 
688                                 j, (void*)offset, (void*)info );
689             if (!info) {
690                if (verb) fprintf ( stderr, " ZERO\n" );
691                S = 0;
692             } else {
693                /* First see if it is a nameless local symbol. */
694                if (stab[ ELF32_R_SYM(info)].st_name == 0) {
695                   if (verb) fprintf ( stderr, "(noname)  ");
696                   S = (Elf32_Addr)(ehdrC
697                                    + shdr[stab[ELF32_R_SYM(info)].st_shndx ].sh_offset
698                                    + stab[ELF32_R_SYM(info)].st_value
699                                   );
700                   strcpy ( symbol, "(noname)");
701                } else {
702                   /* No?  Perhaps it's a named symbol in this file. */
703                   strcpy ( symbol, strtab+stab[ ELF32_R_SYM(info)].st_name );
704                   if (verb) fprintf ( stderr, "`%s'  ", symbol );
705                   S = (Elf32_Addr)ocLookupSym ( oc, symbol );
706                   if (!S) {
707                      /* No?  Ok, too hard.  Hand the problem to the client. 
708                         And if that fails, we're outta options.
709                      */
710                      S = (Elf32_Addr)(oc->clientLookup ( symbol ) );
711                   }
712                }
713                if (verb) fprintf ( stderr, "resolves to %p\n", (void*)S );
714                if (!S) {
715                   char errtxt[2000];
716                   strcpy(errtxt,oc->objFileName);
717                   strcat(errtxt,": unresolvable reference to: ");
718                   strcat(errtxt,symbol);
719                   oc->errMsg(errtxt);
720                   return FALSE;
721                }
722             }
723             /* fprintf ( stderr, "Reloc: P = %p   S = %p   A = %p\n\n",
724                          (void*)P, (void*)S, (void*)A ); 
725             */
726             switch (ELF32_R_TYPE(info)) {
727                case R_386_32:   *pP = S + A;     break;
728                case R_386_PC32: *pP = S + A - P; break;
729                default: fprintf(stderr, 
730                                 "unhandled ELF relocation type %d\n",
731                                 ELF32_R_TYPE(info));
732                         oc->errMsg("unhandled ELF relocation type");
733                         return FALSE;
734             }
735
736          }
737       }
738       else
739       if (shdr[i].sh_type == SHT_RELA) {
740          oc->errMsg("RelA style reloc table -- not yet done");
741          return FALSE;
742       }
743    }
744
745    return TRUE;
746 }
747
748
749 #endif /* defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS) */
750
751
752
753 /*-------------------------------------------------------------------------*/