[project @ 2000-03-07 16:18:25 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 <ctype.h>
19 #include <assert.h>
20 #include "config.h"                             /* for linux_TARGET_OS etc */
21 #include "object.h"
22
23
24 #if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
25 static int ocVerifyImage_ELF    ( ObjectCode* oc, int verb );
26 static int ocGetNames_ELF       ( ObjectCode* oc, int verb );
27 static int ocResolve_ELF        ( ObjectCode* oc, int verb );
28 #elif defined(cygwin32_TARGET_OS)
29 static int ocVerifyImage_PEi386 ( ObjectCode* oc, int verb );
30 static int ocGetNames_PEi386    ( ObjectCode* oc, int verb );
31 static int ocResolve_PEi386     ( ObjectCode* oc, int verb );
32 #endif
33
34 static char* hackyAppend ( char* s1, char* s2 );
35 static int   sortSymbols ( ObjectCode* oc );
36
37
38 /* --------------------------------------------------------------------------
39  * Arch-independent interface to the runtime linker
40  * ------------------------------------------------------------------------*/
41
42 ObjectCode*  ocNew ( void  (*errMsg)(char*),
43                      void* (*clientLookup)(char*),
44                      char*  objFileName,
45                      int    objFileSize )
46 {
47    ObjectCode* oc     = malloc(sizeof(ObjectCode));
48    if (!oc) {
49       errMsg("ocNew: can't allocate memory for object code record");
50       return NULL;
51    }
52
53 #  if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
54    oc->formatName = "ELF";
55 #  elif defined(cygwin32_TARGET_OS)
56    oc->formatName = "PEi386";
57 #  else
58    free(oc);
59    errMsg("ocNew: not implemented on this platform");
60    return NULL;
61 #  endif
62
63    oc->status         = OBJECT_NOTINUSE;
64    oc->objFileName    = objFileName;
65    oc->objFileSize    = objFileSize;
66    oc->errMsg         = errMsg;
67    oc->clientLookup   = clientLookup;
68
69    oc->oImage         = malloc ( objFileSize );
70    if (!oc->oImage) {
71       free(oc);
72       errMsg("ocNew: can't allocate memory for object code");
73       return NULL;
74    }
75    oc->oTab           = NULL;
76    oc->sizeoTab       = 0;
77    oc->usedoTab       = 0;
78    oc->sectionTab     = NULL;
79    oc->sizesectionTab = 0;
80    oc->usedsectionTab = 0;
81    oc->next           = NULL;
82
83    return oc;
84 }
85                             
86
87 int ocLoadImage ( ObjectCode* oc, int verb )
88 {
89    int   n;
90    FILE* f;
91    assert (oc && oc->status==OBJECT_NOTINUSE);
92    if (verb) fprintf(stderr, "ocLoadImage %s\n", oc->objFileName );
93    f = fopen(oc->objFileName, "rb");
94    if (!f) {
95        (oc->errMsg(hackyAppend("ocLoadImage: can't read: ",
96                                oc->objFileName)));
97        return 0;
98    }
99    n = fread ( oc->oImage, 1, oc->objFileSize, f );
100    if (n != oc->objFileSize) {
101       fclose(f);
102       oc->errMsg(hackyAppend("ocLoadImage: I/O error whilst reading: ",
103                              oc->objFileName));
104       return 0;
105    }
106    oc->status = OBJECT_OIMAGE;
107    if (verb) fprintf(stderr, "ocLoadImage %s: read %d bytes\n", 
108                      oc->objFileName, oc->objFileSize );
109    return 1;
110 }
111
112
113 /* returns 1 if ok, 0 if error */
114 int ocVerifyImage ( ObjectCode* oc, int verb )
115 {
116    int ret;
117    assert (oc && oc->status==OBJECT_OIMAGE);
118    if (verb) fprintf(stderr, "ocVerifyImage: begin\n");
119 #  if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
120    ret = ocVerifyImage_ELF ( oc, verb );
121 #  elif defined(cygwin32_TARGET_OS)
122    ret = ocVerifyImage_PEi386 ( oc, verb );
123 #  else
124    oc->errMsg("ocVerifyImage: not implemented on this platform");
125    return 0;
126 #  endif
127    if (verb) fprintf(stderr, "ocVerifyImage: done, status = %d", ret);
128
129    if (ret) oc->status = OBJECT_VERIFIED;
130    return ret;
131 }
132
133
134 /* returns 1 if ok, 0 if error */
135 int ocGetNames ( ObjectCode* oc, int verb )
136 {
137    int ret;
138    assert (oc && oc->status==OBJECT_VERIFIED);
139    if (verb) fprintf(stderr, "ocGetNames: begin\n");
140 #  if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
141    ret = ocGetNames_ELF ( oc, verb );
142 #  elif defined(cygwin32_TARGET_OS)
143    ret = ocGetNames_PEi386 ( oc, verb );
144 #  else
145    oc->errMsg("ocGetNames: not implemented on this platform");
146    return 0;
147 #  endif
148    if (verb) fprintf(stderr, "ocGetNames: done, status = %d\n", ret);
149    if (ret) ret = sortSymbols(oc);
150    if (ret) oc->status = OBJECT_HAVENAMES;
151    return ret;
152 }
153
154
155 /* returns 1 if ok, 0 if error */
156 int ocResolve ( ObjectCode* oc, int verb )
157 {
158    int ret;
159    assert (oc && oc->status==OBJECT_HAVENAMES);
160    if (verb) fprintf(stderr, "ocResolve: begin\n");
161 #  if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
162    ret = ocResolve_ELF ( oc, verb );
163 #  elif defined(cygwin32_TARGET_OS)
164    ret = ocResolve_PEi386 ( oc, verb );
165 #  else
166    oc->errMsg("ocResolve: not implemented on this platform");
167    return 0;
168 #  endif
169    if (verb) fprintf(stderr, "ocResolve: done, status = %d\n", ret);
170    if (ret) oc->status = OBJECT_RESOLVED;
171    return ret;
172 }
173
174
175 void ocFree ( ObjectCode* oc )
176 {
177    if (oc) {
178       if (oc->oImage)     free(oc->oImage);
179       if (oc->oTab)       free(oc->oTab);
180       if (oc->sectionTab) free(oc->sectionTab);
181       free(oc);
182    }
183 }
184
185
186 /* --------------------------------------------------------------------------
187  * Simple, dynamically expandable association tables
188  * ------------------------------------------------------------------------*/
189
190 /* A bit tricky.  Assumes that if tab==NULL, then 
191    currUsed and *currSize must be zero.
192    Returns NULL if expansion failed.
193 */
194 static void* genericExpand ( void* tab, 
195                              int*  currSize, int  currUsed,
196                              int   initSize, int  elemSize )
197 {
198    int   size2;
199    void* tab2;
200    if (currUsed < *currSize) return tab;
201    size2 = (*currSize == 0) ? initSize : (2 * *currSize);
202    tab2 = malloc ( size2 * elemSize );
203    if (!tab2) return NULL;
204    if (*currSize > 0)
205       memcpy ( tab2, tab, elemSize * *currSize );
206    *currSize = size2;
207    if (tab) free ( tab );
208    return tab2;
209 }
210
211
212 /* returns 1 if success, 0 if error */
213 static int addSymbol ( ObjectCode* oc, char* nm, void* ad )
214 {
215    OSym* newTab
216       = genericExpand ( oc->oTab, 
217                         &(oc->sizeoTab),
218                         oc->usedoTab,
219                         8, sizeof(OSym) );
220
221    if (!newTab) {
222       oc->errMsg("addSymbol: malloc failed whilst expanding table");
223       return 0;
224    }
225    oc->oTab = newTab;
226    oc->oTab[ oc->usedoTab ].nm = nm;
227    oc->oTab[ oc->usedoTab ].ad = ad;
228    oc->usedoTab++;
229    return 1;
230 }
231
232
233 /* Reorder symbol table so that symbols are in alphabetical order.
234    Detects an error if, after sorting, any two symbols are the same,
235    since this would imply that the same symbol has been inserted more 
236    than once.  Returns 1 if success, 0 if error.
237 */
238 static int sortSymbols ( ObjectCode* oc )
239 {
240    static int incs[14] 
241       = { 1, 4, 13, 40, 121, 364, 1093, 3280,
242           9841, 29524, 88573, 265720, 797161, 2391484 };
243
244    int lo = 0;
245    int hi = oc->usedoTab-1;
246    int i, j, h, bigN, hp;
247    OSym v;
248
249    bigN = hi - lo + 1; if (bigN < 2) return 1;
250    hp = 0; while (incs[hp] < bigN) hp++; hp--;
251
252    for (; hp >= 0; hp--) {
253       h = incs[hp];
254       i = lo + h;
255       while (1) {
256          if (i > hi) break;
257          v = oc->oTab[i];
258          j = i;
259          while (strcmp(oc->oTab[j-h].nm, v.nm) > 0) {
260             oc->oTab[j] = oc->oTab[j-h];
261             j = j - h;
262             if (j <= (lo + h - 1)) break;
263          }
264          oc->oTab[j] = v;
265          i++;
266       }
267    }
268
269    for (i = 1; i < oc->usedoTab; i++) {
270       j = strcmp(oc->oTab[i-1].nm, oc->oTab[i].nm);
271       if (j  > 0) { 
272          oc->errMsg("sortSymbols: sorting failed"); 
273          return 0;
274       }
275       if (j == 0) {
276          oc->errMsg("sortSymbols: duplicate symbols in object file");
277          return 0;
278       }
279    }
280
281    return 1;
282 }
283
284
285 /* returns 1 if success, 0 if error */
286 static int addSection ( ObjectCode* oc, void* start, void* end, OSectionKind sect )
287 {
288    OSection* newTab
289       = genericExpand ( oc->sectionTab,
290                         &(oc->sizesectionTab),
291                         oc->usedsectionTab,
292                         4, sizeof(OSection) );
293    if (!newTab) {
294       oc->errMsg("addSection: malloc failed whilst expanding table");
295       return 0;
296    }
297    oc->sectionTab = newTab;
298    oc->sectionTab[ oc->usedsectionTab ].start = start;
299    oc->sectionTab[ oc->usedsectionTab ].end   = end;
300    oc->sectionTab[ oc->usedsectionTab ].kind  = sect;
301    oc->usedsectionTab++;
302    return 1;
303 }
304
305
306 void* ocLookupSym ( ObjectCode* oc, char* sym )
307 {
308    int lo, hi, mid, cmp;
309
310    assert(oc);
311    if (oc->status != OBJECT_HAVENAMES 
312        && oc->status != OBJECT_RESOLVED) {
313       oc->errMsg("ocLookupSym: no symbols available");
314       return NULL;
315    }
316
317    /* Originally used a sequential search; should still work
318    for (i = 0; i < oc->usedoTab; i++) {
319       if (0)
320          fprintf ( stderr, 
321                    "ocLookupSym: request %s, table has %s\n",
322                    sym, oc->oTab[i].nm );
323       if (0==strcmp(sym,oc->oTab[i].nm))
324          return oc->oTab[i].ad;
325    }
326    */
327
328    lo = 0; 
329    hi = oc->usedoTab-1;
330    while (1) {
331       /* Invariant: the unsearched area is oc->oTab[lo .. hi] inclusive. */
332       if (hi < lo) return NULL;
333       mid = (hi + lo) / 2;
334       cmp = strcmp(sym, oc->oTab[mid].nm);
335       if (cmp == 0) return oc->oTab[mid].ad;
336       if (cmp < 0) hi = mid-1;
337       if (cmp > 0) lo = mid+1;
338    }
339 }
340
341
342 char* ocLookupAddr ( ObjectCode* oc, void* addr )
343 {
344    int i;
345
346    assert(oc);
347    if (oc->status != OBJECT_HAVENAMES 
348        && oc->status != OBJECT_RESOLVED) {
349       oc->errMsg("ocLookupAddr: no symbols available");
350       return NULL;
351    }
352
353    for (i = 0; i < oc->usedoTab; i++) {
354       if (addr == oc->oTab[i].ad)
355          return oc->oTab[i].nm;
356    }
357    return NULL;
358 }
359
360
361 OSectionKind ocLookupSection ( ObjectCode* oc, void* addr )
362 {
363    int i;
364
365    assert(oc);
366    if (oc->status != OBJECT_HAVENAMES 
367        && oc->status != OBJECT_RESOLVED) {
368       oc->errMsg("ocLookupSection: no symbols available");
369       return HUGS_SECTIONKIND_NOINFOAVAIL;
370    }
371
372
373    for (i = 0; i < oc->usedsectionTab; i++) {
374       if (oc->sectionTab[i].start <= addr 
375           && addr <= oc->sectionTab[i].end)
376          return oc->sectionTab[i].kind;
377    }
378
379    return HUGS_SECTIONKIND_NOINFOAVAIL;
380 }
381
382
383 /* Ghastly append which leaks space.  But we only use it for
384    error messages -- that's my excuse.
385 */
386 static char* hackyAppend ( char* s1, char* s2 )
387 {
388    char* res = malloc ( 4 + strlen(s1) + strlen(s2) );
389    if (!res) {
390       fprintf ( stderr, "hugs: fatal: hackyAppend\n\t%s\n\t%s\n", s1, s2 );
391       assert(res);
392    }
393    strcpy(res,s1);
394    strcat(res,s2);
395    return res;
396 }
397
398 /* --------------------------------------------------------------------------
399  * PEi386 specifics (cygwin32)
400  * ------------------------------------------------------------------------*/
401
402 /* The information for this linker comes from 
403       Microsoft Portable Executable 
404       and Common Object File Format Specification
405       revision 5.1 January 1998
406    which SimonM says comes from the MS Developer Network CDs.
407 */
408       
409
410 #if defined(cygwin32_TARGET_OS)
411
412 #define FALSE 0
413 #define TRUE  1
414
415
416 typedef unsigned char  UChar;
417 typedef unsigned short UInt16;
418 typedef unsigned int   UInt32;
419 typedef          int   Int32;
420
421
422 typedef 
423    struct {
424       UInt16 Machine;
425       UInt16 NumberOfSections;
426       UInt32 TimeDateStamp;
427       UInt32 PointerToSymbolTable;
428       UInt32 NumberOfSymbols;
429       UInt16 SizeOfOptionalHeader;
430       UInt16 Characteristics;
431    }
432    COFF_header;
433
434 #define sizeof_COFF_header 20
435
436
437 typedef 
438    struct {
439       UChar  Name[8];
440       UInt32 VirtualSize;
441       UInt32 VirtualAddress;
442       UInt32 SizeOfRawData;
443       UInt32 PointerToRawData;
444       UInt32 PointerToRelocations;
445       UInt32 PointerToLinenumbers;
446       UInt16 NumberOfRelocations;
447       UInt16 NumberOfLineNumbers;
448       UInt32 Characteristics; 
449    }
450    COFF_section;
451
452 #define sizeof_COFF_section 40
453
454
455 typedef
456    struct {
457       UChar  Name[8];
458       UInt32 Value;
459       UInt16 SectionNumber;
460       UInt16 Type;
461       UChar  StorageClass;
462       UChar  NumberOfAuxSymbols;
463    }
464    COFF_symbol;
465
466 #define sizeof_COFF_symbol 18
467
468
469 typedef
470    struct {
471       UInt32 VirtualAddress;
472       UInt32 SymbolTableIndex;
473       UInt16 Type;
474    }
475    COFF_reloc;
476
477 #define sizeof_COFF_reloc 10
478
479
480 /* From PE spec doc, section 3.3.2 */
481 #define IMAGE_FILE_RELOCS_STRIPPED     0x0001
482 #define IMAGE_FILE_EXECUTABLE_IMAGE    0x0002
483 #define IMAGE_FILE_DLL                 0x2000
484 #define IMAGE_FILE_SYSTEM              0x1000
485 #define IMAGE_FILE_BYTES_REVERSED_HI   0x8000
486 #define IMAGE_FILE_BYTES_REVERSED_LO   0x0080
487 #define IMAGE_FILE_32BIT_MACHINE       0x0100
488
489 /* From PE spec doc, section 5.4.2 and 5.4.4 */
490 #define IMAGE_SYM_CLASS_EXTERNAL       2
491 #define IMAGE_SYM_CLASS_STATIC         3
492 #define IMAGE_SYM_UNDEFINED            0
493
494 /* From PE spec doc, section 4.1 */
495 #define IMAGE_SCN_CNT_CODE             0x00000020
496 #define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
497
498 /* From PE spec doc, section 5.2.1 */
499 #define IMAGE_REL_I386_DIR32           0x0006
500 #define IMAGE_REL_I386_REL32           0x0014
501
502
503 /* We use myindex to calculate array addresses, rather than
504    simply doing the normal subscript thing.  That's because
505    some of the above structs have sizes which are not 
506    a whole number of words.  GCC rounds their sizes up to a
507    whole number of words, which means that the address calcs
508    arising from using normal C indexing or pointer arithmetic
509    are just plain wrong.  Sigh.
510 */
511 static UChar* myindex ( int scale, int index, void* base )
512 {
513    return
514       ((UChar*)base) + scale * index;
515 }
516
517
518 static void printName ( UChar* name, UChar* strtab )
519 {
520    if (name[0]==0 && name[1]==0 && name[2]==0 && name[3]==0) {
521       UInt32 strtab_offset = * (UInt32*)(name+4);
522       fprintf ( stderr, "%s", strtab + strtab_offset );
523    } else {
524       int i;
525       for (i = 0; i < 8; i++) {
526          if (name[i] == 0) break;
527          fprintf ( stderr, "%c", name[i] );
528       }
529    }
530 }
531
532
533 static void copyName ( UChar* name, UChar* strtab, 
534                        UChar* dst, int dstSize )
535 {
536    if (name[0]==0 && name[1]==0 && name[2]==0 && name[3]==0) {
537       UInt32 strtab_offset = * (UInt32*)(name+4);
538       strncpy ( dst, strtab+strtab_offset, dstSize );
539       dst[dstSize-1] = 0;
540    } else {
541       int i = 0;
542       while (1) {
543          if (i >= 8) break;
544          if (name[i] == 0) break;
545          dst[i] = name[i];
546          i++;
547       }
548       dst[i] = 0;
549    }
550 }
551
552
553 static UChar* cstring_from_COFF_symbol_name ( UChar* name, 
554                                               UChar* strtab )
555 {
556    UChar* newstr;
557    /* If the string is longer than 8 bytes, look in the
558       string table for it -- this will be correctly zero terminated. 
559    */
560    if (name[0]==0 && name[1]==0 && name[2]==0 && name[3]==0) {
561       UInt32 strtab_offset = * (UInt32*)(name+4);
562       return ((UChar*)strtab) + strtab_offset;
563    }
564    /* Otherwise, if shorter than 8 bytes, return the original,
565       which by defn is correctly terminated.
566    */
567    if (name[7]==0) return name;
568    /* The annoying case: 8 bytes.  Copy into a temporary
569       (which is never freed ...)
570    */
571    newstr = malloc(9);
572    if (newstr) {
573       strncpy(newstr,name,8);
574       newstr[8] = 0;
575    }
576    return newstr;
577 }
578
579
580 /* Just compares the short names (first 8 chars) */
581 static COFF_section* findPEi386SectionCalled ( ObjectCode* oc,
582                                                char* name )
583 {
584    int i;
585    COFF_header* hdr 
586       = (COFF_header*)(oc->oImage);
587    COFF_section* sectab 
588       = (COFF_section*) (
589            ((UChar*)(oc->oImage)) 
590            + sizeof_COFF_header + hdr->SizeOfOptionalHeader
591         );
592    for (i = 0; i < hdr->NumberOfSections; i++) {
593       UChar* n1;
594       UChar* n2;
595       COFF_section* section_i 
596          = (COFF_section*)
597            myindex ( sizeof_COFF_section, i, sectab );
598       n1 = (UChar*) &(section_i->Name);
599       n2 = name;
600       if (n1[0]==n2[0] && n1[1]==n2[1] && n1[2]==n2[2] && 
601           n1[3]==n2[3] && n1[4]==n2[4] && n1[5]==n2[5] && 
602           n1[6]==n2[6] && n1[7]==n2[7])
603          return section_i;
604    }
605
606    return NULL;
607 }
608
609
610 static void zapTrailingAtSign ( UChar* sym )
611 {
612    int i, j;
613    if (sym[0] == 0) return;
614    i = 0; 
615    while (sym[i] != 0) i++;
616    i--;
617    j = i;
618    while (j > 0 && isdigit(sym[j])) j--;
619    if (j > 0 && sym[j] == '@' && j != i) sym[j] = 0;
620 }
621
622
623 static int ocVerifyImage_PEi386 ( ObjectCode* oc, int verb )
624 {
625    int i, j;
626    COFF_header*  hdr;
627    COFF_section* sectab;
628    COFF_symbol*  symtab;
629    UChar*        strtab;
630
631    hdr = (COFF_header*)(oc->oImage);
632    sectab = (COFF_section*) (
633                ((UChar*)(oc->oImage)) 
634                + sizeof_COFF_header + hdr->SizeOfOptionalHeader
635             );
636    symtab = (COFF_symbol*) (
637                ((UChar*)(oc->oImage))
638                + hdr->PointerToSymbolTable 
639             );
640    strtab = ((UChar*)(oc->oImage))
641             + hdr->PointerToSymbolTable
642             + hdr->NumberOfSymbols * sizeof_COFF_symbol;
643
644    if (hdr->Machine != 0x14c) {
645       oc->errMsg("Not x86 PEi386");
646       return FALSE;
647    }
648    if (hdr->SizeOfOptionalHeader != 0) {
649       oc->errMsg("PEi386 with nonempty optional header");
650       return FALSE;
651    }
652    if ( /* (hdr->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) || */
653         (hdr->Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) ||
654         (hdr->Characteristics & IMAGE_FILE_DLL) ||
655         (hdr->Characteristics & IMAGE_FILE_SYSTEM) ) {
656       oc->errMsg("Not a PEi386 object file");
657       return FALSE;
658    }
659    if ( (hdr->Characteristics & IMAGE_FILE_BYTES_REVERSED_HI) ||
660         !(hdr->Characteristics & IMAGE_FILE_32BIT_MACHINE) ) {
661       oc->errMsg("Invalid PEi386 word size or endiannness");
662       return FALSE;
663    }
664
665    if (!verb) return TRUE;
666    /* No further verification after this point; only debug printing. */
667
668    fprintf ( stderr, 
669              "sectab offset = %d\n", ((UChar*)sectab) - ((UChar*)hdr) );
670    fprintf ( stderr, 
671              "symtab offset = %d\n", ((UChar*)symtab) - ((UChar*)hdr) );
672    fprintf ( stderr, 
673              "strtab offset = %d\n", ((UChar*)strtab) - ((UChar*)hdr) );
674
675    fprintf ( stderr, "\n" );
676    fprintf ( stderr, 
677              "Machine:           0x%x\n", (UInt32)(hdr->Machine) );
678    fprintf ( stderr, 
679              "# sections:        %d\n",   (UInt32)(hdr->NumberOfSections) );
680    fprintf ( stderr,
681              "time/date:         0x%x\n", (UInt32)(hdr->TimeDateStamp) );
682    fprintf ( stderr,
683              "symtab offset:     %d\n",   (UInt32)(hdr->PointerToSymbolTable) );
684    fprintf ( stderr, 
685              "# symbols:         %d\n",   (UInt32)(hdr->NumberOfSymbols) );
686    fprintf ( stderr, 
687              "sz of opt hdr:     %d\n",   (UInt32)(hdr->SizeOfOptionalHeader) );
688    fprintf ( stderr,
689              "characteristics:   0x%x\n", (UInt32)(hdr->Characteristics) );
690
691    fprintf ( stderr, "\n" );
692    fprintf ( stderr, "string table has size 0x%x\n", * (UInt32*)strtab );
693    fprintf ( stderr, "---START of string table---\n");
694    for (i = 4; i < *(UInt32*)strtab; i++) {
695       if (strtab[i] == 0) 
696          fprintf ( stderr, "\n"); else 
697          fprintf( stderr, "%c", strtab[i] );
698    }
699    fprintf ( stderr, "--- END  of string table---\n");
700
701    fprintf ( stderr, "\n" );
702    for (i = 0; i < hdr->NumberOfSections; i++) {
703       COFF_reloc* reltab;
704       COFF_section* sectab_i
705          = (COFF_section*)
706            myindex ( sizeof_COFF_section, i, sectab );
707       fprintf ( stderr, 
708                 "\n"
709                 "section %d\n"
710                 "     name `",
711                 i 
712               );
713       printName ( sectab_i->Name, strtab );
714       fprintf ( stderr, 
715                 "'\n"
716                 "    vsize %d\n"
717                 "    vaddr %d\n"
718                 "  data sz %d\n"
719                 " data off %d\n"
720                 "  num rel %d\n"
721                 "  off rel %d\n",
722                 sectab_i->VirtualSize,
723                 sectab_i->VirtualAddress,
724                 sectab_i->SizeOfRawData,
725                 sectab_i->PointerToRawData,
726                 sectab_i->NumberOfRelocations,
727                 sectab_i->PointerToRelocations
728               );
729       reltab = (COFF_reloc*) (
730                   ((UChar*)(oc->oImage)) + sectab_i->PointerToRelocations
731                );
732       for (j = 0; j < sectab_i->NumberOfRelocations; j++) {
733          COFF_symbol* sym;
734          COFF_reloc* rel = (COFF_reloc*)
735                            myindex ( sizeof_COFF_reloc, j, reltab );
736          fprintf ( stderr, 
737                    "        type 0x%-4x   vaddr 0x%-8x   name `",
738                    (UInt32)rel->Type, 
739                    rel->VirtualAddress );
740          sym = (COFF_symbol*)
741                myindex ( sizeof_COFF_symbol, rel->SymbolTableIndex, symtab );
742          printName ( sym->Name, strtab );
743          fprintf ( stderr, "'\n" );
744       }
745       fprintf ( stderr, "\n" );
746    }
747
748
749    fprintf ( stderr, "\n" );
750    i = 0;
751    while (1) {
752       COFF_symbol* symtab_i;
753       if (i >= hdr->NumberOfSymbols) break;
754       symtab_i = (COFF_symbol*)
755                  myindex ( sizeof_COFF_symbol, i, symtab );
756       fprintf ( stderr, 
757                 "symbol %d\n"
758                 "     name `",
759                 i 
760               );
761       printName ( symtab_i->Name, strtab );
762       fprintf ( stderr, 
763                 "'\n"
764                 "    value 0x%x\n"
765                 "     sec# %d\n"
766                 "     type 0x%x\n"
767                 "   sclass 0x%x\n"
768                 "     nAux %d\n",
769                 symtab_i->Value,
770                 (Int32)(symtab_i->SectionNumber) - 1,
771                 (UInt32)symtab_i->Type,
772                 (UInt32)symtab_i->StorageClass,
773                 (UInt32)symtab_i->NumberOfAuxSymbols 
774               );
775       i += symtab_i->NumberOfAuxSymbols;
776       i++;
777    }
778
779    fprintf ( stderr, "\n" );
780
781    return TRUE;
782 }
783
784
785 static int ocGetNames_PEi386 ( ObjectCode* oc, int verb )
786 {
787    COFF_header*  hdr;
788    COFF_section* sectab;
789    COFF_symbol*  symtab;
790    UChar*        strtab;
791
792    UChar* sname;
793    void*  addr;
794    int    i;
795    
796    hdr = (COFF_header*)(oc->oImage);
797    sectab = (COFF_section*) (
798                ((UChar*)(oc->oImage)) 
799                + sizeof_COFF_header + hdr->SizeOfOptionalHeader
800             );
801    symtab = (COFF_symbol*) (
802                ((UChar*)(oc->oImage))
803                + hdr->PointerToSymbolTable 
804             );
805    strtab = ((UChar*)(oc->oImage))
806             + hdr->PointerToSymbolTable
807             + hdr->NumberOfSymbols * sizeof_COFF_symbol;
808
809    /* Copy exported symbols into the ObjectCode. */
810    i = 0;
811    while (1) {
812       COFF_symbol* symtab_i;
813       if (i >= hdr->NumberOfSymbols) break;
814       symtab_i = (COFF_symbol*)
815                  myindex ( sizeof_COFF_symbol, i, symtab );
816
817       if (symtab_i->StorageClass == IMAGE_SYM_CLASS_EXTERNAL &&
818           symtab_i->SectionNumber != IMAGE_SYM_UNDEFINED) {
819
820          /* This symbol is global and defined, viz, exported */
821          COFF_section* sectabent;
822
823          sname = cstring_from_COFF_symbol_name ( 
824                     symtab_i->Name, strtab 
825                  );
826          if (!sname) {
827             oc->errMsg("Out of memory when copying PEi386 symbol");
828             return FALSE;
829          }
830
831          /* for IMAGE_SYMCLASS_EXTERNAL 
832                 && !IMAGE_SYM_UNDEFINED,
833             the address of the symbol is: 
834                 address of relevant section + offset in section
835          */
836          sectabent = (COFF_section*)
837                      myindex ( sizeof_COFF_section, 
838                                symtab_i->SectionNumber-1,
839                                sectab );
840          addr = ((UChar*)(oc->oImage))
841                 + (sectabent->PointerToRawData
842                    + symtab_i->Value);
843          /* fprintf ( stderr, "addSymbol %p `%s'\n", addr,sname); */
844          if (!addSymbol(oc,sname,addr)) return FALSE;
845       }
846       i += symtab_i->NumberOfAuxSymbols;
847       i++;
848    }
849
850    /* Copy section information into the ObjectCode. */
851    for (i = 0; i < hdr->NumberOfSections; i++) {
852       UChar* start;
853       UChar* end;
854
855       OSectionKind kind 
856          = HUGS_SECTIONKIND_OTHER;
857       COFF_section* sectab_i
858          = (COFF_section*)
859            myindex ( sizeof_COFF_section, i, sectab );
860       /* fprintf ( stderr, "section name = %s\n", sectab_i->Name ); */
861
862 #if 0
863       /* I'm sure this is the Right Way to do it.  However, the 
864          alternative of testing the sectab_i->Name field seems to
865          work ok with Cygwin.
866       */
867       if (sectab_i->Characteristics & IMAGE_SCN_CNT_CODE || 
868           sectab_i->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
869          kind = HUGS_SECTIONKIND_CODE_OR_RODATA;
870 #endif
871
872       if (0==strcmp(".text",sectab_i->Name))
873          kind = HUGS_SECTIONKIND_CODE_OR_RODATA;
874       if (0==strcmp(".data",sectab_i->Name) ||
875           0==strcmp(".bss",sectab_i->Name))
876          kind = HUGS_SECTIONKIND_RWDATA;
877
878       start = ((UChar*)(oc->oImage)) 
879               + sectab_i->PointerToRawData;
880       end   = start 
881               + sectab_i->SizeOfRawData - 1;
882
883       if (kind != HUGS_SECTIONKIND_OTHER) {
884          addSection ( oc, start, end, kind );
885       } else {
886          fprintf ( stderr, "unknown section name = `%s'\n", 
887                    sectab_i->Name);
888          oc->errMsg("Unknown PEi386 section name");
889          return FALSE;
890       }
891    }
892
893    return TRUE;   
894 }
895
896
897 static int ocResolve_PEi386 ( ObjectCode* oc, int verb )
898 {
899    COFF_header*  hdr;
900    COFF_section* sectab;
901    COFF_symbol*  symtab;
902    UChar*        strtab;
903
904    UInt32        A;
905    UInt32        S;
906    UInt32*       pP;
907
908    int i, j;
909    char symbol[1000]; // ToDo
910    
911    hdr = (COFF_header*)(oc->oImage);
912    sectab = (COFF_section*) (
913                ((UChar*)(oc->oImage)) 
914                + sizeof_COFF_header + hdr->SizeOfOptionalHeader
915             );
916    symtab = (COFF_symbol*) (
917                ((UChar*)(oc->oImage))
918                + hdr->PointerToSymbolTable 
919             );
920    strtab = ((UChar*)(oc->oImage))
921             + hdr->PointerToSymbolTable
922             + hdr->NumberOfSymbols * sizeof_COFF_symbol;
923
924    for (i = 0; i < hdr->NumberOfSections; i++) {
925       COFF_section* sectab_i
926          = (COFF_section*)
927            myindex ( sizeof_COFF_section, i, sectab );
928       COFF_reloc* reltab
929          = (COFF_reloc*) (
930               ((UChar*)(oc->oImage)) + sectab_i->PointerToRelocations
931            );
932       for (j = 0; j < sectab_i->NumberOfRelocations; j++) {
933          COFF_symbol* sym;
934          COFF_reloc* reltab_j 
935             = (COFF_reloc*)
936               myindex ( sizeof_COFF_reloc, j, reltab );
937
938          /* the location to patch */
939          pP = (UInt32*)(
940                  ((UChar*)(oc->oImage)) 
941                  + (sectab_i->PointerToRawData 
942                     + reltab_j->VirtualAddress)
943               );
944          /* the existing contents of pP */
945          A = *pP;
946          /* the symbol to connect to */
947          sym = (COFF_symbol*)
948                myindex ( sizeof_COFF_symbol, 
949                          reltab_j->SymbolTableIndex, symtab );
950          if (verb) {
951             fprintf ( stderr, 
952                    "reloc sec %2d num %3d:  type 0x%-4x   "
953                    "vaddr 0x%-8x   name `",
954                    i, j,
955                    (UInt32)reltab_j->Type, 
956                    reltab_j->VirtualAddress );
957             printName ( sym->Name, strtab );
958             fprintf ( stderr, "'\n" );
959          }
960
961          if (sym->StorageClass == IMAGE_SYM_CLASS_STATIC) {
962             COFF_section* section_sym 
963                = findPEi386SectionCalled ( oc, sym->Name );
964             if (!section_sym) {
965                fprintf ( stderr, "bad section = `%s'\n", sym->Name );
966                oc->errMsg("Can't find abovementioned PEi386 section");
967                return FALSE;
968             }
969             S = ((UInt32)(oc->oImage))
970                 + (section_sym->PointerToRawData
971                    + sym->Value);
972          } else {
973          copyName ( sym->Name, strtab, symbol, 1000 );
974          zapTrailingAtSign ( symbol );
975          S = (UInt32) ocLookupSym ( oc, symbol );
976          if (S == 0) 
977             S = (UInt32)(oc->clientLookup ( symbol ));
978          if (S == 0) {
979             char errtxt[2000];
980             strcpy(errtxt,oc->objFileName);
981             strcat(errtxt,": unresolvable reference to: ");
982             strcat(errtxt,symbol);
983             oc->errMsg(errtxt);
984             return FALSE;
985          }
986          }
987
988          switch (reltab_j->Type) {
989             case IMAGE_REL_I386_DIR32: 
990                *pP = A + S; 
991                break;
992             case IMAGE_REL_I386_REL32:
993                /* Tricky.  We have to insert a displacement at
994                   pP which, when added to the PC for the _next_
995                   insn, gives the address of the target (S).
996                   Problem is to know the address of the next insn
997                   when we only know pP.  We assume that this
998                   literal field is always the last in the insn,
999                   so that the address of the next insn is pP+4
1000                   -- hence the constant 4.
1001                   Also I don't know if A should be added, but so
1002                   far it has always been zero.
1003                */
1004                assert(A==0);
1005                *pP = S - ((UInt32)pP) - 4;
1006                break;
1007             default: 
1008                fprintf(stderr, 
1009                        "unhandled PEi386 relocation type %d\n",
1010                        reltab_j->Type);
1011                oc->errMsg("unhandled PEi386 relocation type");
1012                return FALSE;
1013          }
1014
1015       }
1016    }
1017    
1018    return TRUE;
1019 }
1020
1021 #endif /* defined(cygwin32_TARGET_OS) */
1022
1023
1024 /* --------------------------------------------------------------------------
1025  * ELF specifics (Linux, Solaris)
1026  * ------------------------------------------------------------------------*/
1027
1028 #if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
1029
1030 #define FALSE 0
1031 #define TRUE  1
1032
1033 #include <elf.h>
1034
1035 static char* findElfSection ( void* objImage, Elf32_Word sh_type )
1036 {
1037    int i;
1038    char* ehdrC = (char*)objImage;
1039    Elf32_Ehdr* ehdr = ( Elf32_Ehdr*)ehdrC;
1040    Elf32_Shdr* shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
1041    char* ptr = NULL;
1042    for (i = 0; i < ehdr->e_shnum; i++) {
1043       if (shdr[i].sh_type == sh_type &&
1044           i !=  ehdr->e_shstrndx) {
1045          ptr = ehdrC + shdr[i].sh_offset;
1046          break;
1047       }
1048    }
1049    return ptr;
1050 }
1051
1052
1053 static int ocVerifyImage_ELF ( ObjectCode* oc, int verb )
1054 {
1055    Elf32_Shdr* shdr;
1056    Elf32_Sym*  stab;
1057    int i, j, nent, nstrtab, nsymtabs;
1058    char* sh_strtab;
1059    char* strtab;
1060
1061    char*       ehdrC = (char*)(oc->oImage);
1062    Elf32_Ehdr* ehdr  = ( Elf32_Ehdr*)ehdrC;
1063
1064    if (ehdr->e_ident[EI_MAG0] != ELFMAG0 ||
1065        ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
1066        ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
1067        ehdr->e_ident[EI_MAG3] != ELFMAG3) {
1068       oc->errMsg("Not an ELF header");
1069       return FALSE;
1070    }
1071    if (verb) fprintf ( stderr, "Is an ELF header\n" );
1072
1073    if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) {
1074       oc->errMsg("Not 32 bit ELF" );
1075       return FALSE;
1076    }
1077    if (verb) fprintf ( stderr, "Is 32 bit ELF\n" );
1078
1079    if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) {
1080       if (verb) fprintf ( stderr, "Is little-endian\n" );
1081    } else
1082    if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) {
1083       if (verb) fprintf ( stderr, "Is big-endian\n" );
1084    } else {
1085       oc->errMsg("Unknown endiannness");
1086       return FALSE;
1087    }
1088
1089    if (ehdr->e_type != ET_REL) {
1090       oc->errMsg("Not a relocatable object (.o) file");
1091       return FALSE;
1092    }
1093    if (verb) fprintf ( stderr, "Is a relocatable object (.o) file\n" );
1094
1095    if (verb) fprintf ( stderr, "Architecture is " );
1096    switch (ehdr->e_machine) {
1097       case EM_386:   if (verb) fprintf ( stderr, "x86\n" ); break;
1098       case EM_SPARC: if (verb) fprintf ( stderr, "sparc\n" ); break;
1099       default:       if (verb) fprintf ( stderr, "unknown\n" ); 
1100                      oc->errMsg("Unknown architecture");
1101                      return FALSE;
1102    }
1103
1104    if (verb) 
1105    fprintf ( stderr,
1106              "\nSection header table: start %d, n_entries %d, ent_size %d\n", 
1107              ehdr->e_shoff, ehdr->e_shnum, ehdr->e_shentsize  );
1108
1109    assert (ehdr->e_shentsize == sizeof(Elf32_Shdr));
1110
1111    shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
1112
1113    if (ehdr->e_shstrndx == SHN_UNDEF) {
1114       oc->errMsg("No section header string table");
1115       return FALSE;
1116    } else {
1117       if (verb) fprintf (  stderr,"Section header string table is section %d\n", 
1118                           ehdr->e_shstrndx);
1119       sh_strtab = ehdrC + shdr[ehdr->e_shstrndx].sh_offset;
1120    }
1121
1122    for (i = 0; i < ehdr->e_shnum; i++) {
1123       if (verb) fprintf ( stderr, "%2d:  ", i );
1124       if (verb) fprintf ( stderr, "type=%2d  ", shdr[i].sh_type );
1125       if (verb) fprintf ( stderr, "size=%4d  ", shdr[i].sh_size );
1126       if (verb) fprintf ( stderr, "offs=%4d  ", shdr[i].sh_offset );
1127       if (verb) fprintf ( stderr, "  (%p .. %p)  ",
1128                ehdrC + shdr[i].sh_offset, 
1129                ehdrC + shdr[i].sh_offset + shdr[i].sh_size - 1);
1130
1131       if (shdr[i].sh_type == SHT_REL  && verb) fprintf ( stderr, "Rel  " ); else
1132       if (shdr[i].sh_type == SHT_RELA && verb) fprintf ( stderr, "RelA " ); else
1133       if (verb)                                fprintf ( stderr, "     " );
1134       if (sh_strtab && verb) 
1135          fprintf ( stderr, "sname=%s", sh_strtab + shdr[i].sh_name );
1136       if (verb) fprintf ( stderr, "\n" );
1137    }
1138
1139    if (verb) fprintf ( stderr, "\n\nString tables\n" );
1140    strtab = NULL;
1141    nstrtab = 0;
1142    for (i = 0; i < ehdr->e_shnum; i++) {
1143       if (shdr[i].sh_type == SHT_STRTAB &&
1144           i !=  ehdr->e_shstrndx) {
1145          if (verb) 
1146             fprintf ( stderr, "   section %d is a normal string table\n", i );
1147          strtab = ehdrC + shdr[i].sh_offset;
1148          nstrtab++;
1149       }
1150    }  
1151    if (nstrtab != 1) {
1152       oc->errMsg("WARNING: no string tables, or too many");
1153       return FALSE;
1154    }
1155
1156    nsymtabs = 0;
1157    if (verb) fprintf ( stderr, "\n\nSymbol tables\n" ); 
1158    for (i = 0; i < ehdr->e_shnum; i++) {
1159       if (shdr[i].sh_type != SHT_SYMTAB) continue;
1160       if (verb) fprintf ( stderr, "section %d is a symbol table\n", i );
1161       nsymtabs++;
1162       stab = (Elf32_Sym*) (ehdrC + shdr[i].sh_offset);
1163       nent = shdr[i].sh_size / sizeof(Elf32_Sym);
1164       if (verb) fprintf ( stderr, "   number of entries is apparently %d (%d rem)\n",
1165                nent,
1166                shdr[i].sh_size % sizeof(Elf32_Sym)
1167              );
1168       if (0 != shdr[i].sh_size % sizeof(Elf32_Sym)) {
1169          oc->errMsg("non-integral number of symbol table entries");
1170          return FALSE;
1171       }
1172       for (j = 0; j < nent; j++) {
1173          if (verb) fprintf ( stderr, "   %2d  ", j );
1174          if (verb) fprintf ( stderr, "  sec=%-5d  size=%-3d  val=%-5p  ", 
1175                              (int)stab[j].st_shndx,
1176                              (int)stab[j].st_size,
1177                              (char*)stab[j].st_value );
1178
1179          if (verb) fprintf ( stderr, "type=" );
1180          switch (ELF32_ST_TYPE(stab[j].st_info)) {
1181             case STT_NOTYPE:  if (verb) fprintf ( stderr, "notype " ); break;
1182             case STT_OBJECT:  if (verb) fprintf ( stderr, "object " ); break;
1183             case STT_FUNC  :  if (verb) fprintf ( stderr, "func   " ); break;
1184             case STT_SECTION: if (verb) fprintf ( stderr, "section" ); break;
1185             case STT_FILE:    if (verb) fprintf ( stderr, "file   " ); break;
1186             default:          if (verb) fprintf ( stderr, "?      " ); break;
1187          }
1188          if (verb) fprintf ( stderr, "  " );
1189
1190          if (verb) fprintf ( stderr, "bind=" );
1191          switch (ELF32_ST_BIND(stab[j].st_info)) {
1192             case STB_LOCAL :  if (verb) fprintf ( stderr, "local " ); break;
1193             case STB_GLOBAL:  if (verb) fprintf ( stderr, "global" ); break;
1194             case STB_WEAK  :  if (verb) fprintf ( stderr, "weak  " ); break;
1195             default:          if (verb) fprintf ( stderr, "?     " ); break;
1196          }
1197          if (verb) fprintf ( stderr, "  " );
1198
1199          if (verb) fprintf ( stderr, "name=%s\n", strtab + stab[j].st_name );
1200       }
1201    }
1202
1203    if (nsymtabs == 0) {
1204       oc->errMsg("Didn't find any symbol tables");
1205       return FALSE;
1206    }
1207
1208    return TRUE;
1209 }
1210
1211
1212 static int ocGetNames_ELF ( ObjectCode* oc, int verb )
1213 {
1214    int i, j, k, nent;
1215    Elf32_Sym* stab;
1216
1217    char*       ehdrC      = (char*)(oc->oImage);
1218    Elf32_Ehdr* ehdr       = (Elf32_Ehdr*)ehdrC;
1219    char*       strtab     = findElfSection ( ehdrC, SHT_STRTAB );
1220    Elf32_Shdr* shdr       = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
1221    char*       sh_strtab  = ehdrC + shdr[ehdr->e_shstrndx].sh_offset;
1222
1223    if (!strtab) {
1224       oc->errMsg("ELF: no strtab!");
1225       return FALSE;
1226    }
1227
1228    k = 0;
1229    for (i = 0; i < ehdr->e_shnum; i++) {
1230
1231       /* make a HugsDLSection entry for relevant sections */
1232       OSectionKind kind = HUGS_SECTIONKIND_OTHER;
1233       if (0==strcmp(".data",sh_strtab+shdr[i].sh_name) ||
1234           0==strcmp(".data1",sh_strtab+shdr[i].sh_name))
1235          kind = HUGS_SECTIONKIND_RWDATA;
1236       if (0==strcmp(".text",sh_strtab+shdr[i].sh_name) ||
1237           0==strcmp(".rodata",sh_strtab+shdr[i].sh_name) ||
1238           0==strcmp(".rodata1",sh_strtab+shdr[i].sh_name))
1239          kind = HUGS_SECTIONKIND_CODE_OR_RODATA;
1240       if (kind != HUGS_SECTIONKIND_OTHER)
1241          addSection (
1242             oc,
1243             ehdrC + shdr[i].sh_offset, 
1244             ehdrC + shdr[i].sh_offset + shdr[i].sh_size - 1,
1245             kind
1246          );
1247
1248       if (shdr[i].sh_type != SHT_SYMTAB) continue;
1249
1250       /* copy stuff into this module's object symbol table */
1251       stab = (Elf32_Sym*) (ehdrC + shdr[i].sh_offset);
1252       nent = shdr[i].sh_size / sizeof(Elf32_Sym);
1253       for (j = 0; j < nent; j++) {
1254          if ( ( ELF32_ST_BIND(stab[j].st_info)==STB_GLOBAL ||
1255                 ELF32_ST_BIND(stab[j].st_info)==STB_LOCAL
1256               )
1257               &&
1258               ( ELF32_ST_TYPE(stab[j].st_info)==STT_FUNC ||
1259                 ELF32_ST_TYPE(stab[j].st_info)==STT_OBJECT)
1260               /* || ELF32_ST_TYPE(stab[j].st_info)==STT_NOTYPE */
1261               ) {
1262             char* nm = strtab + stab[j].st_name;
1263             char* ad = ehdrC 
1264                        + shdr[ stab[j].st_shndx ].sh_offset
1265                        + stab[j].st_value;
1266             assert(nm);
1267             assert(ad);
1268             if (verb)
1269                fprintf(stderr, "addOTabName: %10p  %s %s\n",
1270                        ad, oc->objFileName, nm );
1271             if (!addSymbol ( oc, nm, ad )) return FALSE;
1272          }
1273          else 
1274          if (verb)
1275             fprintf(stderr, "skipping `%s'\n", strtab + stab[j].st_name );
1276       }
1277    }
1278
1279    return TRUE;
1280 }
1281
1282
1283 static int ocResolve_ELF ( ObjectCode* oc, int verb )
1284 {
1285    char symbol[1000]; // ToDo
1286    char* strtab;
1287    int   i, j;
1288    Elf32_Sym*  stab = NULL;
1289    char*       ehdrC = (char*)(oc->oImage);
1290    Elf32_Ehdr* ehdr = (Elf32_Ehdr*) ehdrC;
1291    Elf32_Shdr* shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
1292    Elf32_Word* targ;
1293
1294    /* first find "the" symbol table */
1295    stab = (Elf32_Sym*) findElfSection ( ehdrC, SHT_SYMTAB );
1296
1297    /* also go find the string table */
1298    strtab = findElfSection ( ehdrC, SHT_STRTAB );
1299
1300    if (!stab || !strtab) {
1301       oc->errMsg("can't find string or symbol table");
1302       return FALSE; 
1303    }
1304
1305    for (i = 0; i < ehdr->e_shnum; i++) {
1306       if (shdr[i].sh_type == SHT_REL ) {
1307          Elf32_Rel*  rtab = (Elf32_Rel*) (ehdrC + shdr[i].sh_offset);
1308          int         nent = shdr[i].sh_size / sizeof(Elf32_Rel);
1309          int target_shndx = shdr[i].sh_info;
1310          int symtab_shndx = shdr[i].sh_link;
1311          stab  = (Elf32_Sym*) (ehdrC + shdr[ symtab_shndx ].sh_offset);
1312          targ  = (Elf32_Word*)(ehdrC + shdr[ target_shndx ].sh_offset);
1313          if (verb)
1314          fprintf ( stderr,
1315                   "relocations for section %d using symtab %d\n",
1316                   target_shndx, symtab_shndx );
1317          for (j = 0; j < nent; j++) {
1318             Elf32_Addr offset = rtab[j].r_offset;
1319             Elf32_Word info   = rtab[j].r_info;
1320
1321             Elf32_Addr  P = ((Elf32_Addr)targ) + offset;
1322             Elf32_Word* pP = (Elf32_Word*)P;
1323             Elf32_Addr  A = *pP;
1324             Elf32_Addr  S;
1325
1326             if (verb) fprintf ( stderr, "Rel entry %3d is raw(%6p %6p)   ", 
1327                                 j, (void*)offset, (void*)info );
1328             if (!info) {
1329                if (verb) fprintf ( stderr, " ZERO\n" );
1330                S = 0;
1331             } else {
1332                /* First see if it is a nameless local symbol. */
1333                if (stab[ ELF32_R_SYM(info)].st_name == 0) {
1334                   if (verb) fprintf ( stderr, "(noname)  ");
1335                   S = (Elf32_Addr)(ehdrC
1336                                    + shdr[stab[ELF32_R_SYM(info)].st_shndx ].sh_offset
1337                                    + stab[ELF32_R_SYM(info)].st_value
1338                                   );
1339                   strcpy ( symbol, "(noname)");
1340                } else {
1341                   /* No?  Perhaps it's a named symbol in this file. */
1342                   strcpy ( symbol, strtab+stab[ ELF32_R_SYM(info)].st_name );
1343                   if (verb) fprintf ( stderr, "`%s'  ", symbol );
1344                   S = (Elf32_Addr)ocLookupSym ( oc, symbol );
1345                   if (!S) {
1346                      /* No?  Ok, too hard.  Hand the problem to the client. 
1347                         And if that fails, we're outta options.
1348                      */
1349                      S = (Elf32_Addr)(oc->clientLookup ( symbol ) );
1350                   }
1351                }
1352                if (verb) fprintf ( stderr, "resolves to %p\n", (void*)S );
1353                if (!S) {
1354                   char errtxt[2000];
1355                   strcpy(errtxt,oc->objFileName);
1356                   strcat(errtxt,": unresolvable reference to: ");
1357                   strcat(errtxt,symbol);
1358                   oc->errMsg(errtxt);
1359                   return FALSE;
1360                }
1361             }
1362             /* fprintf ( stderr, "Reloc: P = %p   S = %p   A = %p\n\n",
1363                          (void*)P, (void*)S, (void*)A ); 
1364             */
1365             switch (ELF32_R_TYPE(info)) {
1366                case R_386_32:   *pP = S + A;     break;
1367                case R_386_PC32: *pP = S + A - P; break;
1368                default: fprintf(stderr, 
1369                                 "unhandled ELF relocation type %d\n",
1370                                 ELF32_R_TYPE(info));
1371                         oc->errMsg("unhandled ELF relocation type");
1372                         return FALSE;
1373             }
1374
1375          }
1376       }
1377       else
1378       if (shdr[i].sh_type == SHT_RELA) {
1379          oc->errMsg("RelA style reloc table -- not yet done");
1380          return FALSE;
1381       }
1382    }
1383
1384    return TRUE;
1385 }
1386
1387
1388 #endif /* defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS) */
1389
1390
1391
1392 /*-------------------------------------------------------------------------*/