[project @ 2000-04-11 09:40:19 by simonmar]
[ghc-hetmet.git] / ghc / interpreter / object.c
index 11f8976..4da4e06 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 #include <assert.h>
 #include "config.h"                             /* for linux_TARGET_OS etc */
 #include "object.h"
 
 
 #if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
-static int ocVerifyImage_ELF ( ObjectCode* oc, int verb );
-static int ocGetNames_ELF    ( ObjectCode* oc, int verb );
-static int ocResolve_ELF     ( ObjectCode* oc, int verb );
+static int ocVerifyImage_ELF    ( ObjectCode* oc, int verb );
+static int ocGetNames_ELF       ( ObjectCode* oc, int verb );
+static int ocResolve_ELF        ( ObjectCode* oc, int verb );
+#elif defined(cygwin32_TARGET_OS)
+static int ocVerifyImage_PEi386 ( ObjectCode* oc, int verb );
+static int ocGetNames_PEi386    ( ObjectCode* oc, int verb );
+static int ocResolve_PEi386     ( ObjectCode* oc, int verb );
 #endif
 
 static char* hackyAppend ( char* s1, char* s2 );
@@ -34,12 +39,13 @@ static int   sortSymbols ( ObjectCode* oc );
  * Arch-independent interface to the runtime linker
  * ------------------------------------------------------------------------*/
 
-ObjectCode*  ocNew ( void  (*errMsg)(char*),
-                     void* (*clientLookup)(char*),
+ObjectCode*  ocNew ( void   (*errMsg)(char*),
+                     void*  (*clientLookup)(char*),
+                     int    (*clientWantsSymbol)(char*),
                      char*  objFileName,
                      int    objFileSize )
 {
-   ObjectCode* oc     = malloc(sizeof(ObjectCode));
+   ObjectCode* oc        = malloc(sizeof(ObjectCode));
    if (!oc) {
       errMsg("ocNew: can't allocate memory for object code record");
       return NULL;
@@ -47,31 +53,34 @@ ObjectCode*  ocNew ( void  (*errMsg)(char*),
 
 #  if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
    oc->formatName = "ELF";
+#  elif defined(cygwin32_TARGET_OS)
+   oc->formatName = "PEi386";
 #  else
    free(oc);
    errMsg("ocNew: not implemented on this platform");
    return NULL;
 #  endif
 
-   oc->status         = OBJECT_NOTINUSE;
-   oc->objFileName    = objFileName;
-   oc->objFileSize    = objFileSize;
-   oc->errMsg         = errMsg;
-   oc->clientLookup   = clientLookup;
+   oc->status            = OBJECT_NOTINUSE;
+   oc->objFileName       = objFileName;
+   oc->objFileSize       = objFileSize;
+   oc->errMsg            = errMsg;
+   oc->clientLookup      = clientLookup;
+   oc->clientWantsSymbol = clientWantsSymbol;
 
-   oc->oImage         = malloc ( objFileSize );
+   oc->oImage            = malloc ( objFileSize );
    if (!oc->oImage) {
       free(oc);
       errMsg("ocNew: can't allocate memory for object code");
       return NULL;
    }
-   oc->oTab           = NULL;
-   oc->sizeoTab       = 0;
-   oc->usedoTab       = 0;
-   oc->sectionTab     = NULL;
-   oc->sizesectionTab = 0;
-   oc->usedsectionTab = 0;
-   oc->next           = NULL;
+   oc->oTab              = NULL;
+   oc->sizeoTab          = 0;
+   oc->usedoTab          = 0;
+   oc->sectionTab        = NULL;
+   oc->sizesectionTab    = 0;
+   oc->usedsectionTab    = 0;
+   oc->next              = NULL;
 
    return oc;
 }
@@ -111,6 +120,8 @@ int ocVerifyImage ( ObjectCode* oc, int verb )
    if (verb) fprintf(stderr, "ocVerifyImage: begin\n");
 #  if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
    ret = ocVerifyImage_ELF ( oc, verb );
+#  elif defined(cygwin32_TARGET_OS)
+   ret = ocVerifyImage_PEi386 ( oc, verb );
 #  else
    oc->errMsg("ocVerifyImage: not implemented on this platform");
    return 0;
@@ -130,6 +141,8 @@ int ocGetNames ( ObjectCode* oc, int verb )
    if (verb) fprintf(stderr, "ocGetNames: begin\n");
 #  if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
    ret = ocGetNames_ELF ( oc, verb );
+#  elif defined(cygwin32_TARGET_OS)
+   ret = ocGetNames_PEi386 ( oc, verb );
 #  else
    oc->errMsg("ocGetNames: not implemented on this platform");
    return 0;
@@ -149,6 +162,8 @@ int ocResolve ( ObjectCode* oc, int verb )
    if (verb) fprintf(stderr, "ocResolve: begin\n");
 #  if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
    ret = ocResolve_ELF ( oc, verb );
+#  elif defined(cygwin32_TARGET_OS)
+   ret = ocResolve_PEi386 ( oc, verb );
 #  else
    oc->errMsg("ocResolve: not implemented on this platform");
    return 0;
@@ -199,7 +214,12 @@ static void* genericExpand ( void* tab,
 /* returns 1 if success, 0 if error */
 static int addSymbol ( ObjectCode* oc, char* nm, void* ad )
 {
-   OSym* newTab
+   OSym* newTab;
+
+   if (oc->clientWantsSymbol && !oc->clientWantsSymbol(nm))
+      return 1;
+
+   newTab
       = genericExpand ( oc->oTab, 
                         &(oc->sizeoTab),
                         oc->usedoTab,
@@ -260,7 +280,8 @@ static int sortSymbols ( ObjectCode* oc )
          return 0;
       }
       if (j == 0) {
-         oc->errMsg("sortSymbols: duplicate symbols in object file");
+         oc->errMsg("sortSymbols: duplicate symbols in object file:");
+         oc->errMsg(oc->oTab[i].nm);
          return 0;
       }
    }
@@ -383,14 +404,640 @@ static char* hackyAppend ( char* s1, char* s2 )
 }
 
 /* --------------------------------------------------------------------------
- * ELF specifics
+ * PEi386 specifics (cygwin32)
  * ------------------------------------------------------------------------*/
 
+/* The information for this linker comes from 
+      Microsoft Portable Executable 
+      and Common Object File Format Specification
+      revision 5.1 January 1998
+   which SimonM says comes from the MS Developer Network CDs.
+*/
+      
+
+#if defined(cygwin32_TARGET_OS)
+
 #define FALSE 0
 #define TRUE  1
 
+
+typedef unsigned char  UChar;
+typedef unsigned short UInt16;
+typedef unsigned int   UInt32;
+typedef          int   Int32;
+
+
+typedef 
+   struct {
+      UInt16 Machine;
+      UInt16 NumberOfSections;
+      UInt32 TimeDateStamp;
+      UInt32 PointerToSymbolTable;
+      UInt32 NumberOfSymbols;
+      UInt16 SizeOfOptionalHeader;
+      UInt16 Characteristics;
+   }
+   COFF_header;
+
+#define sizeof_COFF_header 20
+
+
+typedef 
+   struct {
+      UChar  Name[8];
+      UInt32 VirtualSize;
+      UInt32 VirtualAddress;
+      UInt32 SizeOfRawData;
+      UInt32 PointerToRawData;
+      UInt32 PointerToRelocations;
+      UInt32 PointerToLinenumbers;
+      UInt16 NumberOfRelocations;
+      UInt16 NumberOfLineNumbers;
+      UInt32 Characteristics; 
+   }
+   COFF_section;
+
+#define sizeof_COFF_section 40
+
+
+typedef
+   struct {
+      UChar  Name[8];
+      UInt32 Value;
+      UInt16 SectionNumber;
+      UInt16 Type;
+      UChar  StorageClass;
+      UChar  NumberOfAuxSymbols;
+   }
+   COFF_symbol;
+
+#define sizeof_COFF_symbol 18
+
+
+typedef
+   struct {
+      UInt32 VirtualAddress;
+      UInt32 SymbolTableIndex;
+      UInt16 Type;
+   }
+   COFF_reloc;
+
+#define sizeof_COFF_reloc 10
+
+
+/* From PE spec doc, section 3.3.2 */
+#define IMAGE_FILE_RELOCS_STRIPPED     0x0001
+#define IMAGE_FILE_EXECUTABLE_IMAGE    0x0002
+#define IMAGE_FILE_DLL                 0x2000
+#define IMAGE_FILE_SYSTEM              0x1000
+#define IMAGE_FILE_BYTES_REVERSED_HI   0x8000
+#define IMAGE_FILE_BYTES_REVERSED_LO   0x0080
+#define IMAGE_FILE_32BIT_MACHINE       0x0100
+
+/* From PE spec doc, section 5.4.2 and 5.4.4 */
+#define IMAGE_SYM_CLASS_EXTERNAL       2
+#define IMAGE_SYM_CLASS_STATIC         3
+#define IMAGE_SYM_UNDEFINED            0
+
+/* From PE spec doc, section 4.1 */
+#define IMAGE_SCN_CNT_CODE             0x00000020
+#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
+
+/* From PE spec doc, section 5.2.1 */
+#define IMAGE_REL_I386_DIR32           0x0006
+#define IMAGE_REL_I386_REL32           0x0014
+
+
+/* We use myindex to calculate array addresses, rather than
+   simply doing the normal subscript thing.  That's because
+   some of the above structs have sizes which are not 
+   a whole number of words.  GCC rounds their sizes up to a
+   whole number of words, which means that the address calcs
+   arising from using normal C indexing or pointer arithmetic
+   are just plain wrong.  Sigh.
+*/
+static UChar* myindex ( int scale, int index, void* base )
+{
+   return
+      ((UChar*)base) + scale * index;
+}
+
+
+static void printName ( UChar* name, UChar* strtab )
+{
+   if (name[0]==0 && name[1]==0 && name[2]==0 && name[3]==0) {
+      UInt32 strtab_offset = * (UInt32*)(name+4);
+      fprintf ( stderr, "%s", strtab + strtab_offset );
+   } else {
+      int i;
+      for (i = 0; i < 8; i++) {
+         if (name[i] == 0) break;
+         fprintf ( stderr, "%c", name[i] );
+      }
+   }
+}
+
+
+static void copyName ( UChar* name, UChar* strtab, 
+                       UChar* dst, int dstSize )
+{
+   if (name[0]==0 && name[1]==0 && name[2]==0 && name[3]==0) {
+      UInt32 strtab_offset = * (UInt32*)(name+4);
+      strncpy ( dst, strtab+strtab_offset, dstSize );
+      dst[dstSize-1] = 0;
+   } else {
+      int i = 0;
+      while (1) {
+         if (i >= 8) break;
+         if (name[i] == 0) break;
+         dst[i] = name[i];
+         i++;
+      }
+      dst[i] = 0;
+   }
+}
+
+
+static UChar* cstring_from_COFF_symbol_name ( UChar* name, 
+                                              UChar* strtab )
+{
+   UChar* newstr;
+   /* If the string is longer than 8 bytes, look in the
+      string table for it -- this will be correctly zero terminated. 
+   */
+   if (name[0]==0 && name[1]==0 && name[2]==0 && name[3]==0) {
+      UInt32 strtab_offset = * (UInt32*)(name+4);
+      return ((UChar*)strtab) + strtab_offset;
+   }
+   /* Otherwise, if shorter than 8 bytes, return the original,
+      which by defn is correctly terminated.
+   */
+   if (name[7]==0) return name;
+   /* The annoying case: 8 bytes.  Copy into a temporary
+      (which is never freed ...)
+   */
+   newstr = malloc(9);
+   if (newstr) {
+      strncpy(newstr,name,8);
+      newstr[8] = 0;
+   }
+   return newstr;
+}
+
+
+/* Just compares the short names (first 8 chars) */
+static COFF_section* findPEi386SectionCalled ( ObjectCode* oc,
+                                               char* name )
+{
+   int i;
+   COFF_header* hdr 
+      = (COFF_header*)(oc->oImage);
+   COFF_section* sectab 
+      = (COFF_section*) (
+           ((UChar*)(oc->oImage)) 
+           + sizeof_COFF_header + hdr->SizeOfOptionalHeader
+        );
+   for (i = 0; i < hdr->NumberOfSections; i++) {
+      UChar* n1;
+      UChar* n2;
+      COFF_section* section_i 
+         = (COFF_section*)
+           myindex ( sizeof_COFF_section, i, sectab );
+      n1 = (UChar*) &(section_i->Name);
+      n2 = name;
+      if (n1[0]==n2[0] && n1[1]==n2[1] && n1[2]==n2[2] && 
+          n1[3]==n2[3] && n1[4]==n2[4] && n1[5]==n2[5] && 
+          n1[6]==n2[6] && n1[7]==n2[7])
+         return section_i;
+   }
+
+   return NULL;
+}
+
+
+static void zapTrailingAtSign ( UChar* sym )
+{
+   int i, j;
+   if (sym[0] == 0) return;
+   i = 0; 
+   while (sym[i] != 0) i++;
+   i--;
+   j = i;
+   while (j > 0 && isdigit(sym[j])) j--;
+   if (j > 0 && sym[j] == '@' && j != i) sym[j] = 0;
+}
+
+
+static int ocVerifyImage_PEi386 ( ObjectCode* oc, int verb )
+{
+   int i, j;
+   COFF_header*  hdr;
+   COFF_section* sectab;
+   COFF_symbol*  symtab;
+   UChar*        strtab;
+
+   hdr = (COFF_header*)(oc->oImage);
+   sectab = (COFF_section*) (
+               ((UChar*)(oc->oImage)) 
+               + sizeof_COFF_header + hdr->SizeOfOptionalHeader
+            );
+   symtab = (COFF_symbol*) (
+               ((UChar*)(oc->oImage))
+               + hdr->PointerToSymbolTable 
+            );
+   strtab = ((UChar*)(oc->oImage))
+            + hdr->PointerToSymbolTable
+            + hdr->NumberOfSymbols * sizeof_COFF_symbol;
+
+   if (hdr->Machine != 0x14c) {
+      oc->errMsg("Not x86 PEi386");
+      return FALSE;
+   }
+   if (hdr->SizeOfOptionalHeader != 0) {
+      oc->errMsg("PEi386 with nonempty optional header");
+      return FALSE;
+   }
+   if ( /* (hdr->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) || */
+        (hdr->Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) ||
+        (hdr->Characteristics & IMAGE_FILE_DLL) ||
+        (hdr->Characteristics & IMAGE_FILE_SYSTEM) ) {
+      oc->errMsg("Not a PEi386 object file");
+      return FALSE;
+   }
+   if ( (hdr->Characteristics & IMAGE_FILE_BYTES_REVERSED_HI) ||
+        !(hdr->Characteristics & IMAGE_FILE_32BIT_MACHINE) ) {
+      oc->errMsg("Invalid PEi386 word size or endiannness");
+      return FALSE;
+   }
+
+   if (!verb) return TRUE;
+   /* No further verification after this point; only debug printing. */
+
+   fprintf ( stderr, 
+             "sectab offset = %d\n", ((UChar*)sectab) - ((UChar*)hdr) );
+   fprintf ( stderr, 
+             "symtab offset = %d\n", ((UChar*)symtab) - ((UChar*)hdr) );
+   fprintf ( stderr, 
+             "strtab offset = %d\n", ((UChar*)strtab) - ((UChar*)hdr) );
+
+   fprintf ( stderr, "\n" );
+   fprintf ( stderr, 
+             "Machine:           0x%x\n", (UInt32)(hdr->Machine) );
+   fprintf ( stderr, 
+             "# sections:        %d\n",   (UInt32)(hdr->NumberOfSections) );
+   fprintf ( stderr,
+             "time/date:         0x%x\n", (UInt32)(hdr->TimeDateStamp) );
+   fprintf ( stderr,
+             "symtab offset:     %d\n",   (UInt32)(hdr->PointerToSymbolTable) );
+   fprintf ( stderr, 
+             "# symbols:         %d\n",   (UInt32)(hdr->NumberOfSymbols) );
+   fprintf ( stderr, 
+             "sz of opt hdr:     %d\n",   (UInt32)(hdr->SizeOfOptionalHeader) );
+   fprintf ( stderr,
+             "characteristics:   0x%x\n", (UInt32)(hdr->Characteristics) );
+
+   fprintf ( stderr, "\n" );
+   fprintf ( stderr, "string table has size 0x%x\n", * (UInt32*)strtab );
+   fprintf ( stderr, "---START of string table---\n");
+   for (i = 4; i < *(UInt32*)strtab; i++) {
+      if (strtab[i] == 0) 
+         fprintf ( stderr, "\n"); else 
+         fprintf( stderr, "%c", strtab[i] );
+   }
+   fprintf ( stderr, "--- END  of string table---\n");
+
+   fprintf ( stderr, "\n" );
+   for (i = 0; i < hdr->NumberOfSections; i++) {
+      COFF_reloc* reltab;
+      COFF_section* sectab_i
+         = (COFF_section*)
+           myindex ( sizeof_COFF_section, i, sectab );
+      fprintf ( stderr, 
+                "\n"
+                "section %d\n"
+                "     name `",
+                i 
+              );
+      printName ( sectab_i->Name, strtab );
+      fprintf ( stderr, 
+                "'\n"
+                "    vsize %d\n"
+                "    vaddr %d\n"
+                "  data sz %d\n"
+                " data off %d\n"
+                "  num rel %d\n"
+                "  off rel %d\n",
+                sectab_i->VirtualSize,
+                sectab_i->VirtualAddress,
+                sectab_i->SizeOfRawData,
+                sectab_i->PointerToRawData,
+                sectab_i->NumberOfRelocations,
+                sectab_i->PointerToRelocations
+              );
+      reltab = (COFF_reloc*) (
+                  ((UChar*)(oc->oImage)) + sectab_i->PointerToRelocations
+               );
+      for (j = 0; j < sectab_i->NumberOfRelocations; j++) {
+         COFF_symbol* sym;
+         COFF_reloc* rel = (COFF_reloc*)
+                           myindex ( sizeof_COFF_reloc, j, reltab );
+         fprintf ( stderr, 
+                   "        type 0x%-4x   vaddr 0x%-8x   name `",
+                   (UInt32)rel->Type, 
+                   rel->VirtualAddress );
+         sym = (COFF_symbol*)
+               myindex ( sizeof_COFF_symbol, rel->SymbolTableIndex, symtab );
+         printName ( sym->Name, strtab );
+         fprintf ( stderr, "'\n" );
+      }
+      fprintf ( stderr, "\n" );
+   }
+
+
+   fprintf ( stderr, "\n" );
+   i = 0;
+   while (1) {
+      COFF_symbol* symtab_i;
+      if (i >= hdr->NumberOfSymbols) break;
+      symtab_i = (COFF_symbol*)
+                 myindex ( sizeof_COFF_symbol, i, symtab );
+      fprintf ( stderr, 
+                "symbol %d\n"
+                "     name `",
+                i 
+              );
+      printName ( symtab_i->Name, strtab );
+      fprintf ( stderr, 
+                "'\n"
+                "    value 0x%x\n"
+                "     sec# %d\n"
+                "     type 0x%x\n"
+                "   sclass 0x%x\n"
+                "     nAux %d\n",
+                symtab_i->Value,
+                (Int32)(symtab_i->SectionNumber) - 1,
+                (UInt32)symtab_i->Type,
+                (UInt32)symtab_i->StorageClass,
+                (UInt32)symtab_i->NumberOfAuxSymbols 
+              );
+      i += symtab_i->NumberOfAuxSymbols;
+      i++;
+   }
+
+   fprintf ( stderr, "\n" );
+
+   return TRUE;
+}
+
+
+static int ocGetNames_PEi386 ( ObjectCode* oc, int verb )
+{
+   COFF_header*  hdr;
+   COFF_section* sectab;
+   COFF_symbol*  symtab;
+   UChar*        strtab;
+
+   UChar* sname;
+   void*  addr;
+   int    i;
+   
+   hdr = (COFF_header*)(oc->oImage);
+   sectab = (COFF_section*) (
+               ((UChar*)(oc->oImage)) 
+               + sizeof_COFF_header + hdr->SizeOfOptionalHeader
+            );
+   symtab = (COFF_symbol*) (
+               ((UChar*)(oc->oImage))
+               + hdr->PointerToSymbolTable 
+            );
+   strtab = ((UChar*)(oc->oImage))
+            + hdr->PointerToSymbolTable
+            + hdr->NumberOfSymbols * sizeof_COFF_symbol;
+
+   /* Copy exported symbols into the ObjectCode. */
+   i = 0;
+   while (1) {
+      COFF_symbol* symtab_i;
+      if (i >= hdr->NumberOfSymbols) break;
+      symtab_i = (COFF_symbol*)
+                 myindex ( sizeof_COFF_symbol, i, symtab );
+
+      if (symtab_i->StorageClass == IMAGE_SYM_CLASS_EXTERNAL &&
+          symtab_i->SectionNumber != IMAGE_SYM_UNDEFINED) {
+
+         /* This symbol is global and defined, viz, exported */
+         COFF_section* sectabent;
+
+         sname = cstring_from_COFF_symbol_name ( 
+                    symtab_i->Name, strtab 
+                 );
+         if (!sname) {
+            oc->errMsg("Out of memory when copying PEi386 symbol");
+            return FALSE;
+         }
+
+         /* for IMAGE_SYMCLASS_EXTERNAL 
+                && !IMAGE_SYM_UNDEFINED,
+            the address of the symbol is: 
+                address of relevant section + offset in section
+         */
+         sectabent = (COFF_section*)
+                     myindex ( sizeof_COFF_section, 
+                               symtab_i->SectionNumber-1,
+                               sectab );
+         addr = ((UChar*)(oc->oImage))
+                + (sectabent->PointerToRawData
+                   + symtab_i->Value);
+         /* fprintf ( stderr, "addSymbol %p `%s'\n", addr,sname); */
+         if (!addSymbol(oc,sname,addr)) return FALSE;
+      }
+      i += symtab_i->NumberOfAuxSymbols;
+      i++;
+   }
+
+   /* Copy section information into the ObjectCode. */
+   for (i = 0; i < hdr->NumberOfSections; i++) {
+      UChar* start;
+      UChar* end;
+
+      OSectionKind kind 
+         = HUGS_SECTIONKIND_OTHER;
+      COFF_section* sectab_i
+         = (COFF_section*)
+           myindex ( sizeof_COFF_section, i, sectab );
+      /* fprintf ( stderr, "section name = %s\n", sectab_i->Name ); */
+
+#if 0
+      /* I'm sure this is the Right Way to do it.  However, the 
+         alternative of testing the sectab_i->Name field seems to
+         work ok with Cygwin.
+      */
+      if (sectab_i->Characteristics & IMAGE_SCN_CNT_CODE || 
+          sectab_i->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
+         kind = HUGS_SECTIONKIND_CODE_OR_RODATA;
+#endif
+
+      if (0==strcmp(".text",sectab_i->Name))
+         kind = HUGS_SECTIONKIND_CODE_OR_RODATA;
+      if (0==strcmp(".data",sectab_i->Name) ||
+          0==strcmp(".bss",sectab_i->Name))
+         kind = HUGS_SECTIONKIND_RWDATA;
+
+      start = ((UChar*)(oc->oImage)) 
+              + sectab_i->PointerToRawData;
+      end   = start 
+              + sectab_i->SizeOfRawData - 1;
+
+      if (kind != HUGS_SECTIONKIND_OTHER) {
+         addSection ( oc, start, end, kind );
+      } else {
+         fprintf ( stderr, "unknown section name = `%s'\n", 
+                   sectab_i->Name);
+         oc->errMsg("Unknown PEi386 section name");
+         return FALSE;
+      }
+   }
+
+   return TRUE;   
+}
+
+
+static int ocResolve_PEi386 ( ObjectCode* oc, int verb )
+{
+   COFF_header*  hdr;
+   COFF_section* sectab;
+   COFF_symbol*  symtab;
+   UChar*        strtab;
+
+   UInt32        A;
+   UInt32        S;
+   UInt32*       pP;
+
+   int i, j;
+   char symbol[1000]; // ToDo
+   
+   hdr = (COFF_header*)(oc->oImage);
+   sectab = (COFF_section*) (
+               ((UChar*)(oc->oImage)) 
+               + sizeof_COFF_header + hdr->SizeOfOptionalHeader
+            );
+   symtab = (COFF_symbol*) (
+               ((UChar*)(oc->oImage))
+               + hdr->PointerToSymbolTable 
+            );
+   strtab = ((UChar*)(oc->oImage))
+            + hdr->PointerToSymbolTable
+            + hdr->NumberOfSymbols * sizeof_COFF_symbol;
+
+   for (i = 0; i < hdr->NumberOfSections; i++) {
+      COFF_section* sectab_i
+         = (COFF_section*)
+           myindex ( sizeof_COFF_section, i, sectab );
+      COFF_reloc* reltab
+         = (COFF_reloc*) (
+              ((UChar*)(oc->oImage)) + sectab_i->PointerToRelocations
+           );
+      for (j = 0; j < sectab_i->NumberOfRelocations; j++) {
+         COFF_symbol* sym;
+         COFF_reloc* reltab_j 
+            = (COFF_reloc*)
+              myindex ( sizeof_COFF_reloc, j, reltab );
+
+         /* the location to patch */
+         pP = (UInt32*)(
+                 ((UChar*)(oc->oImage)) 
+                 + (sectab_i->PointerToRawData 
+                    + reltab_j->VirtualAddress)
+              );
+         /* the existing contents of pP */
+         A = *pP;
+         /* the symbol to connect to */
+         sym = (COFF_symbol*)
+               myindex ( sizeof_COFF_symbol, 
+                         reltab_j->SymbolTableIndex, symtab );
+         if (verb) {
+            fprintf ( stderr, 
+                   "reloc sec %2d num %3d:  type 0x%-4x   "
+                   "vaddr 0x%-8x   name `",
+                   i, j,
+                   (UInt32)reltab_j->Type, 
+                   reltab_j->VirtualAddress );
+            printName ( sym->Name, strtab );
+            fprintf ( stderr, "'\n" );
+         }
+
+         if (sym->StorageClass == IMAGE_SYM_CLASS_STATIC) {
+            COFF_section* section_sym 
+               = findPEi386SectionCalled ( oc, sym->Name );
+            if (!section_sym) {
+               fprintf ( stderr, "bad section = `%s'\n", sym->Name );
+               oc->errMsg("Can't find abovementioned PEi386 section");
+               return FALSE;
+            }
+            S = ((UInt32)(oc->oImage))
+                + (section_sym->PointerToRawData
+                   + sym->Value);
+         } else {
+         copyName ( sym->Name, strtab, symbol, 1000 );
+         zapTrailingAtSign ( symbol );
+         S = (UInt32) ocLookupSym ( oc, symbol );
+         if (S == 0) 
+            S = (UInt32)(oc->clientLookup ( symbol ));
+         if (S == 0) {
+            char errtxt[2000];
+            strcpy(errtxt,oc->objFileName);
+            strcat(errtxt,": unresolvable reference to: ");
+            strcat(errtxt,symbol);
+            oc->errMsg(errtxt);
+            return FALSE;
+         }
+         }
+
+         switch (reltab_j->Type) {
+            case IMAGE_REL_I386_DIR32: 
+               *pP = A + S; 
+               break;
+            case IMAGE_REL_I386_REL32:
+               /* Tricky.  We have to insert a displacement at
+                  pP which, when added to the PC for the _next_
+                  insn, gives the address of the target (S).
+                  Problem is to know the address of the next insn
+                  when we only know pP.  We assume that this
+                  literal field is always the last in the insn,
+                  so that the address of the next insn is pP+4
+                  -- hence the constant 4.
+                  Also I don't know if A should be added, but so
+                  far it has always been zero.
+              */
+               assert(A==0);
+               *pP = S - ((UInt32)pP) - 4;
+               break;
+            default: 
+               fprintf(stderr, 
+                       "unhandled PEi386 relocation type %d\n",
+                       reltab_j->Type);
+               oc->errMsg("unhandled PEi386 relocation type");
+               return FALSE;
+         }
+
+      }
+   }
+   
+   return TRUE;
+}
+
+#endif /* defined(cygwin32_TARGET_OS) */
+
+
+/* --------------------------------------------------------------------------
+ * ELF specifics (Linux, Solaris)
+ * ------------------------------------------------------------------------*/
+
 #if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
 
+#define FALSE 0
+#define TRUE  1
+
 #include <elf.h>
 
 static char* findElfSection ( void* objImage, Elf32_Word sh_type )
@@ -582,7 +1229,7 @@ static int ocGetNames_ELF ( ObjectCode* oc, int verb )
    char*       sh_strtab  = ehdrC + shdr[ehdr->e_shstrndx].sh_offset;
 
    if (!strtab) {
-      oc->errMsg("no strtab!");
+      oc->errMsg("ELF: no strtab!");
       return FALSE;
    }
 
@@ -631,7 +1278,9 @@ static int ocGetNames_ELF ( ObjectCode* oc, int verb )
                        ad, oc->objFileName, nm );
             if (!addSymbol ( oc, nm, ad )) return FALSE;
          }
-        else fprintf(stderr, "skipping `%s'\n", strtab + stab[j].st_name );
+        else 
+         if (verb)
+            fprintf(stderr, "skipping `%s'\n", strtab + stab[j].st_name );
       }
    }