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