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