[project @ 2000-10-06 15:33:27 by simonmar]
authorsimonmar <unknown>
Fri, 6 Oct 2000 15:33:27 +0000 (15:33 +0000)
committersimonmar <unknown>
Fri, 6 Oct 2000 15:33:27 +0000 (15:33 +0000)
Object file linker for GHCi.

ghc/rts/Linker.c [new file with mode: 0644]
ghc/rts/Linker.h [new file with mode: 0644]

diff --git a/ghc/rts/Linker.c b/ghc/rts/Linker.c
new file mode 100644 (file)
index 0000000..cbe069d
--- /dev/null
@@ -0,0 +1,1450 @@
+/* -----------------------------------------------------------------------------
+ * $Id: Linker.c,v 1.1 2000/10/06 15:33:27 simonmar Exp $
+ *
+ * (c) The GHC Team, 2000
+ *
+ * RTS Object Linker
+ *
+ * ---------------------------------------------------------------------------*/
+
+#include "Rts.h"
+#include "RtsFlags.h"
+#include "HsFFI.h"
+#include "Hash.h"
+#include "Linker.h"
+#include "RtsUtils.h"
+
+/* These two are POSIX headers */
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/* ToDo: configure this */
+#include <dlfcn.h>
+
+/* A bucket in the symbol hash-table.  Primarily, maps symbol names to
+ * absolute addresses.  All symbols from a given module are linked
+ * together, so they can be freed at the same time.  There's also a
+ * bucket link field for the hash table.
+ */
+typedef struct _SymbolVal {
+    char   *lbl;
+    void   *addr;
+} SymbolVal;
+
+typedef enum { OBJECT_LOADED, OBJECT_RESOLVED } OStatus;
+
+/* Indication of section kinds for loaded objects.  Needed by
+   the GC for deciding whether or not a pointer on the stack
+   is a code pointer.
+*/
+typedef enum { SECTIONKIND_CODE_OR_RODATA,
+               SECTIONKIND_RWDATA,
+               SECTIONKIND_OTHER,
+               SECTIONKIND_NOINFOAVAIL } 
+   SectionKind;
+
+typedef struct { void* start; void* end; SectionKind kind; } 
+   Section;
+
+/* Top-level structure for an object module.  One of these is allocated
+ * for each object file in use.
+ */
+typedef struct _ObjectCode {
+    OStatus   status;
+    char*     fileName;
+    int       fileSize;
+    char*     formatName;            /* eg "ELF32", "DLL", "COFF", etc. */
+
+    SymbolVal *symbols;
+    int       n_symbols;
+
+    /* ptr to malloc'd lump of memory holding the obj file */
+    void*     image;
+
+    /* The section-kind entries for this object module.  Dynamically expands. */
+    Section*  sections;
+    int       n_sections;
+    
+    /* Allow a chain of these things */
+    struct _ObjectCode * next;
+} ObjectCode;
+
+
+/* Hash table mapping symbol names to Symbol */
+/*Str*/HashTable *symhash;
+
+/* List of currently loaded objects */
+ObjectCode *objects;
+
+#if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
+static int ocVerifyImage_ELF    ( ObjectCode* oc );
+static int ocGetNames_ELF       ( ObjectCode* oc );
+static int ocResolve_ELF        ( ObjectCode* oc );
+#elif defined(cygwin32_TARGET_OS)              
+static int ocVerifyImage_PEi386 ( ObjectCode* oc );
+static int ocGetNames_PEi386    ( ObjectCode* oc );
+static int ocResolve_PEi386     ( ObjectCode* oc );
+#endif
+
+/* -----------------------------------------------------------------------------
+ * Built-in symbols from the RTS
+ */
+
+#define RTS_SYMBOLS                            \
+      SymX(MainRegTable)                       \
+      Sym(stg_gc_enter_1)                      \
+      Sym(stg_gc_noregs)                       \
+      Sym(stg_gc_seq_1)                                \
+      Sym(stg_gc_d1)                           \
+      Sym(stg_gc_f1)                           \
+      Sym(stg_gc_ut_1_0)                       \
+      Sym(stg_gc_ut_0_1)                       \
+      Sym(stg_gc_unbx_r1)                      \
+      Sym(stg_chk_0)                           \
+      Sym(stg_chk_1)                           \
+      Sym(stg_gen_chk)                         \
+      SymX(stg_exit)                           \
+      SymX(stg_update_PAP)                     \
+      SymX(__ap_2_upd_info)                    \
+      SymX(__ap_3_upd_info)                    \
+      SymX(__ap_4_upd_info)                    \
+      SymX(__ap_5_upd_info)                    \
+      SymX(__ap_6_upd_info)                    \
+      SymX(__ap_7_upd_info)                    \
+      SymX(__ap_8_upd_info)                    \
+      SymX(__sel_0_upd_info)                   \
+      SymX(__sel_1_upd_info)                   \
+      SymX(__sel_2_upd_info)                   \
+      SymX(__sel_3_upd_info)                   \
+      SymX(__sel_4_upd_info)                   \
+      SymX(__sel_5_upd_info)                   \
+      SymX(__sel_6_upd_info)                   \
+      SymX(__sel_7_upd_info)                   \
+      SymX(__sel_8_upd_info)                   \
+      SymX(__sel_9_upd_info)                   \
+      SymX(__sel_10_upd_info)                  \
+      SymX(__sel_11_upd_info)                  \
+      SymX(__sel_12_upd_info)                  \
+      SymX(upd_frame_info)                     \
+      SymX(seq_frame_info)                     \
+      SymX(CAF_BLACKHOLE_info)                 \
+      SymX(IND_STATIC_info)                    \
+      SymX(EMPTY_MVAR_info)                    \
+      SymX(MUT_ARR_PTRS_FROZEN_info)           \
+      SymX(newCAF)                             \
+      SymX(putMVarzh_fast)                     \
+      SymX(newMVarzh_fast)                     \
+      SymX(takeMVarzh_fast)                    \
+      SymX(tryTakeMVarzh_fast)                 \
+      SymX(catchzh_fast)                       \
+      SymX(raisezh_fast)                       \
+      SymX(delayzh_fast)                       \
+      SymX(yieldzh_fast)                       \
+      SymX(killThreadzh_fast)                  \
+      SymX(waitReadzh_fast)                    \
+      SymX(waitWritezh_fast)                   \
+      SymX(CHARLIKE_closure)                   \
+      SymX(INTLIKE_closure)                    \
+      SymX(suspendThread)                      \
+      SymX(resumeThread)                       \
+      SymX(stackOverflow)                      \
+      SymX(int2Integerzh_fast)                 \
+      SymX(ErrorHdrHook)                       \
+      SymX(mkForeignObjzh_fast)                        \
+      SymX(__encodeDouble)                     \
+      SymX(decodeDoublezh_fast)                        \
+      SymX(isDoubleNaN)                                \
+      SymX(isDoubleInfinite)                   \
+      SymX(isDoubleDenormalized)               \
+      SymX(isDoubleNegativeZero)               \
+      SymX(__encodeFloat)                      \
+      SymX(decodeFloatzh_fast)                 \
+      SymX(isFloatNaN)                         \
+      SymX(isFloatInfinite)                    \
+      SymX(isFloatDenormalized)                        \
+      SymX(isFloatNegativeZero)                        \
+      SymX(__int_encodeFloat)                  \
+      SymX(__int_encodeDouble)                 \
+      SymX(__gmpz_cmp_si)                      \
+      SymX(__gmpz_cmp)                         \
+      SymX(__gmpn_gcd_1)                       \
+      SymX(gcdIntegerzh_fast)                  \
+      SymX(newArrayzh_fast)                    \
+      SymX(unsafeThawArrayzh_fast)             \
+      SymX(newDoubleArrayzh_fast)              \
+      SymX(newFloatArrayzh_fast)               \
+      SymX(newAddrArrayzh_fast)                        \
+      SymX(newWordArrayzh_fast)                        \
+      SymX(newIntArrayzh_fast)                 \
+      SymX(newCharArrayzh_fast)                        \
+      SymX(newMutVarzh_fast)                   \
+      SymX(quotRemIntegerzh_fast)              \
+      SymX(quotIntegerzh_fast)                 \
+      SymX(remIntegerzh_fast)                  \
+      SymX(divExactIntegerzh_fast)             \
+      SymX(divModIntegerzh_fast)               \
+      SymX(timesIntegerzh_fast)                        \
+      SymX(minusIntegerzh_fast)                        \
+      SymX(plusIntegerzh_fast)                 \
+      SymX(mkWeakzh_fast)                      \
+      SymX(prog_argv)                          \
+      SymX(prog_argc)                          \
+      SymX(resetNonBlockingFd)                 \
+      SymX(getStablePtr)                       \
+      SymX(stable_ptr_table)                   \
+      SymX(shutdownHaskellAndExit)             \
+      Sym(stg_enterStackTop)                   \
+      SymX(CAF_UNENTERED_entry)                        \
+      Sym(stg_yield_to_Hugs)                   \
+      Sym(StgReturn)                           \
+      Sym(init_stack)                          \
+      SymX(blockAsyncExceptionszh_fast)                \
+      SymX(unblockAsyncExceptionszh_fast)      \
+      Sym(__init_PrelGHC)
+
+/* entirely bogus claims about types of these symbols */
+#define Sym(vvv)  extern void (vvv);
+#define SymX(vvv) /**/
+RTS_SYMBOLS
+#undef Sym
+#undef SymX
+
+#ifdef LEADING_UNDERSCORE
+#define MAYBE_LEADING_UNDERSCORE_STR(s) ("_" s)
+#else
+#define MAYBE_LEADING_UNDERSCORE_STR(s) (s)
+#endif
+
+#define Sym(vvv) { MAYBE_LEADING_UNDERSCORE_STR(#vvv), \
+                    (void*)(&(vvv)) },
+#define SymX(vvv) Sym(vvv)
+
+static SymbolVal rtsSyms[] = {
+      RTS_SYMBOLS
+      { 0, 0 } /* sentinel */
+};
+
+/* -----------------------------------------------------------------------------
+ * initialize the object linker
+ */
+static void *dl_prog_handle;
+
+void
+initLinker( void )
+{
+    SymbolVal *sym;
+
+    symhash = allocStrHashTable();
+
+    /* populate the symbol table with stuff from the RTS */
+    for (sym = rtsSyms; sym->lbl != NULL; sym++) {
+       insertStrHashTable(symhash, sym->lbl, sym);
+    }
+
+    dl_prog_handle = dlopen(NULL, RTLD_LAZY);
+}
+
+/* -----------------------------------------------------------------------------
+ * lookup a symbol in the hash table
+ */  
+void *
+lookupSymbol( char *lbl )
+{
+    SymbolVal *val;
+    val = lookupStrHashTable(symhash, lbl);
+
+    if (val == NULL) {
+       return dlsym(dl_prog_handle, lbl);
+    } else {
+       return val->addr;
+    }
+}
+
+/* -----------------------------------------------------------------------------
+ * Load an obj (populate the global symbol table, but don't resolve yet)
+ *
+ * Returns: 1 if ok, 0 on error.
+ */
+HsInt
+loadObj( char *path )
+{
+   ObjectCode* oc;
+   struct stat st;
+   int r, n;
+   FILE *f;
+
+#ifdef DEBUG
+   /* assert that we haven't already loaded this object */
+   { 
+       ObjectCode *o;
+       for (o = objects; o; o = o->next)
+          ASSERT(strcmp(o->fileName, path));
+   }
+#endif /* DEBUG */   
+
+   oc = stgMallocBytes(sizeof(ObjectCode), "loadObj(oc)");
+
+#  if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
+   oc->formatName = "ELF";
+#  elif defined(cygwin32_TARGET_OS)
+   oc->formatName = "PEi386";
+#  else
+   free(oc);
+   barf("loadObj: not implemented on this platform");
+#  endif
+
+   r = stat(path, &st);
+   if (r == -1) { return 0; }
+
+   oc->fileName          = path;
+   oc->fileSize          = st.st_size;
+   oc->image             = stgMallocBytes( st.st_size, "loadObj(image)" );
+   oc->symbols           = NULL;
+   oc->sections          = NULL;
+
+   /* chain it onto the list of objects */
+   oc->next              = objects;
+   objects               = oc;
+
+   /* load the image into memory */
+   f = fopen(path, "rb");
+   if (!f) {
+       barf("loadObj: can't read `%s'", path);
+   }
+   n = fread ( oc->image, 1, oc->fileSize, f );
+   if (n != oc->fileSize) {
+      fclose(f);
+      barf("loadObj: error whilst reading `%s'", path);
+   }
+
+   /* verify the in-memory image */
+#  if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
+   r = ocVerifyImage_ELF ( oc );
+#  elif defined(cygwin32_TARGET_OS)
+   r = ocVerifyImage_PEi386 ( oc );
+#  else
+   barf("loadObj: no verify method");
+#  endif
+   if (!r) { return r; }
+
+   /* build the symbol list for this image */
+#  if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
+   r = ocGetNames_ELF ( oc );
+#  elif defined(cygwin32_TARGET_OS)
+   r = ocGetNames_PEi386 ( oc );
+#  else
+   barf("loadObj: no getNames method");
+#  endif
+   if (!r) { return r; }
+
+   /* loaded, but not resolved yet */
+   oc->status = OBJECT_LOADED;
+
+   return 1;
+}
+
+/* -----------------------------------------------------------------------------
+ * resolve all the currently unlinked objects in memory
+ *
+ * Returns: 1 if ok, 0 on error.
+ */
+HsInt 
+resolveObjs( void )
+{
+    ObjectCode *oc;
+    int r;
+
+    for (oc = objects; oc; oc = oc->next) {
+       if (oc->status != OBJECT_RESOLVED) {
+#  if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
+           r = ocResolve_ELF ( oc );
+#  elif defined(cygwin32_TARGET_OS)
+           r = ocResolve_PEi386 ( oc );
+#  else
+           barf("link: not implemented on this platform");
+#  endif
+           if (!r) { return r; }
+           oc->status = OBJECT_RESOLVED;
+       }
+    }
+    return 1;
+}
+
+/* -----------------------------------------------------------------------------
+ * delete an object from the pool
+ */
+HsInt
+unloadObj( char *path )
+{
+    ObjectCode *oc;
+
+    for (oc = objects; oc; oc = oc->next) {
+       if (!strcmp(oc->fileName,path)) {
+
+           /* Remove all the mappings for the symbols within this
+            * object..
+            */
+           { 
+               SymbolVal *s;
+               for (s = oc->symbols; s < oc->symbols + oc->n_symbols; s++) {
+                   removeStrHashTable(symhash, s->lbl, NULL);
+               }
+           }
+
+           /* We're going to leave this in place, in case there are
+              any pointers from the heap into it: */
+           /* free(oc->image); */
+           free(oc->symbols);
+           free(oc->sections);
+           free(oc);
+           return 1;
+       }
+    }
+    
+    belch("unloadObj: can't find `%s' to unload", path);
+    return 0;
+}
+
+/* --------------------------------------------------------------------------
+ * 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)
+
+
+
+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->image);
+   COFF_section* sectab 
+      = (COFF_section*) (
+           ((UChar*)(oc->image)) 
+           + 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 i, j;
+   COFF_header*  hdr;
+   COFF_section* sectab;
+   COFF_symbol*  symtab;
+   UChar*        strtab;
+
+   hdr = (COFF_header*)(oc->image);
+   sectab = (COFF_section*) (
+               ((UChar*)(oc->image)) 
+               + sizeof_COFF_header + hdr->SizeOfOptionalHeader
+            );
+   symtab = (COFF_symbol*) (
+               ((UChar*)(oc->image))
+               + hdr->PointerToSymbolTable 
+            );
+   strtab = ((UChar*)(oc->image))
+            + 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->image)) + 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 )
+{
+   COFF_header*  hdr;
+   COFF_section* sectab;
+   COFF_symbol*  symtab;
+   UChar*        strtab;
+
+   UChar* sname;
+   void*  addr;
+   int    i;
+   
+   hdr = (COFF_header*)(oc->image);
+   sectab = (COFF_section*) (
+               ((UChar*)(oc->image)) 
+               + sizeof_COFF_header + hdr->SizeOfOptionalHeader
+            );
+   symtab = (COFF_symbol*) (
+               ((UChar*)(oc->image))
+               + hdr->PointerToSymbolTable 
+            );
+   strtab = ((UChar*)(oc->image))
+            + 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->image))
+                + (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++;
+   }
+
+   oc->sections = stgMallocBytes( NumberOfSections * sizeof(Section), 
+                                   "ocGetNamesPEi386" );
+
+   /* Copy section information into the ObjectCode. */
+   for (i = 0; i < hdr->NumberOfSections; i++) {
+      UChar* start;
+      UChar* end;
+
+      SectionKind kind 
+         = 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 = SECTIONKIND_CODE_OR_RODATA;
+#endif
+
+      if (0==strcmp(".text",sectab_i->Name))
+         kind = SECTIONKIND_CODE_OR_RODATA;
+      if (0==strcmp(".data",sectab_i->Name) ||
+          0==strcmp(".bss",sectab_i->Name))
+         kind = SECTIONKIND_RWDATA;
+
+      start = ((UChar*)(oc->image)) 
+              + sectab_i->PointerToRawData;
+      end   = start 
+              + sectab_i->SizeOfRawData - 1;
+
+      if (kind != 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->image);
+   sectab = (COFF_section*) (
+               ((UChar*)(oc->image)) 
+               + sizeof_COFF_header + hdr->SizeOfOptionalHeader
+            );
+   symtab = (COFF_symbol*) (
+               ((UChar*)(oc->image))
+               + hdr->PointerToSymbolTable 
+            );
+   strtab = ((UChar*)(oc->image))
+            + 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->image)) + 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->image)) 
+                 + (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->image))
+                + (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) {
+            belch("%s: unresolvable reference to `%s'", oc->fileName, symbol);
+            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 )
+{
+   int i;
+   char* ehdrC = (char*)objImage;
+   Elf32_Ehdr* ehdr = ( Elf32_Ehdr*)ehdrC;
+   Elf32_Shdr* shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
+   char* ptr = NULL;
+   for (i = 0; i < ehdr->e_shnum; i++) {
+      if (shdr[i].sh_type == sh_type &&
+          i !=  ehdr->e_shstrndx) {
+         ptr = ehdrC + shdr[i].sh_offset;
+         break;
+      }
+   }
+   return ptr;
+}
+
+
+static int
+ocVerifyImage_ELF ( ObjectCode* oc )
+{
+   Elf32_Shdr* shdr;
+   Elf32_Sym*  stab;
+   int i, j, nent, nstrtab, nsymtabs;
+   char* sh_strtab;
+   char* strtab;
+
+   char*       ehdrC = (char*)(oc->image);
+   Elf32_Ehdr* ehdr  = ( Elf32_Ehdr*)ehdrC;
+
+   if (ehdr->e_ident[EI_MAG0] != ELFMAG0 ||
+       ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
+       ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
+       ehdr->e_ident[EI_MAG3] != ELFMAG3) {
+      belch("ocVerifyImage_ELF: not an ELF header");
+      return 0;
+   }
+   IF_DEBUG(linker,belch( "Is an ELF header" ));
+
+   if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) {
+      belch("ocVerifyImage_ELF: not 32 bit ELF" );
+      return 0;
+   }
+
+   IF_DEBUG(linker,belch( "Is 32 bit ELF" ));
+
+   if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) {
+       IF_DEBUG(linker,belch( "Is little-endian" ));
+   } else
+   if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) {
+       IF_DEBUG(linker,belch( "Is big-endian" ));
+   } else {
+       belch("ocVerifyImage_ELF: unknown endiannness");
+       return 0;
+   }
+
+   if (ehdr->e_type != ET_REL) {
+      belch("ocVerifyImage_ELF: not a relocatable object (.o) file");
+      return 0;
+   }
+   IF_DEBUG(linker, belch( "Is a relocatable object (.o) file" ));
+
+   IF_DEBUG(linker,belch( "Architecture is " ));
+   switch (ehdr->e_machine) {
+      case EM_386:   IF_DEBUG(linker,belch( "x86" )); break;
+      case EM_SPARC: IF_DEBUG(linker,belch( "sparc" )); break;
+      default:       IF_DEBUG(linker,belch( "unknown" )); 
+                     belch("ocVerifyImage_ELF: unknown architecture");
+                     return 0;
+   }
+
+   IF_DEBUG(linker,belch(
+             "\nSection header table: start %d, n_entries %d, ent_size %d", 
+             ehdr->e_shoff, ehdr->e_shnum, ehdr->e_shentsize  ));
+
+   ASSERT (ehdr->e_shentsize == sizeof(Elf32_Shdr));
+
+   shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
+
+   if (ehdr->e_shstrndx == SHN_UNDEF) {
+      belch("ocVerifyImage_ELF: no section header string table");
+      return 0;
+   } else {
+      IF_DEBUG(linker,belch( "Section header string table is section %d", 
+                          ehdr->e_shstrndx));
+      sh_strtab = ehdrC + shdr[ehdr->e_shstrndx].sh_offset;
+   }
+
+   for (i = 0; i < ehdr->e_shnum; i++) {
+      IF_DEBUG(linker,fprintf(stderr, "%2d:  ", i ));
+      IF_DEBUG(linker,fprintf(stderr, "type=%2d  ", shdr[i].sh_type ));
+      IF_DEBUG(linker,fprintf(stderr, "size=%4d  ", shdr[i].sh_size ));
+      IF_DEBUG(linker,fprintf(stderr, "offs=%4d  ", shdr[i].sh_offset ));
+      IF_DEBUG(linker,fprintf(stderr, "  (%p .. %p)  ",
+               ehdrC + shdr[i].sh_offset, 
+                     ehdrC + shdr[i].sh_offset + shdr[i].sh_size - 1));
+
+      if (shdr[i].sh_type == SHT_REL) {
+         IF_DEBUG(linker,fprintf(stderr, "Rel  " ));
+      } else if (shdr[i].sh_type == SHT_RELA) {
+         IF_DEBUG(linker,fprintf(stderr, "RelA " ));
+      } else {
+         IF_DEBUG(linker,fprintf(stderr,"     "));
+      }
+      if (sh_strtab) {
+         IF_DEBUG(linker,fprintf(stderr, "sname=%s\n", sh_strtab + shdr[i].sh_name ));
+      }
+   }
+
+   IF_DEBUG(linker,belch( "\nString tables" ));
+   strtab = NULL;
+   nstrtab = 0;
+   for (i = 0; i < ehdr->e_shnum; i++) {
+      if (shdr[i].sh_type == SHT_STRTAB &&
+          i !=  ehdr->e_shstrndx) {
+         IF_DEBUG(linker,belch("   section %d is a normal string table", i ));
+         strtab = ehdrC + shdr[i].sh_offset;
+         nstrtab++;
+      }
+   }  
+   if (nstrtab != 1) {
+      belch("ocVerifyImage_ELF: no string tables, or too many");
+      return 0;
+   }
+
+   nsymtabs = 0;
+   IF_DEBUG(linker,belch( "\nSymbol tables" )); 
+   for (i = 0; i < ehdr->e_shnum; i++) {
+      if (shdr[i].sh_type != SHT_SYMTAB) continue;
+      IF_DEBUG(linker,belch( "section %d is a symbol table", i ));
+      nsymtabs++;
+      stab = (Elf32_Sym*) (ehdrC + shdr[i].sh_offset);
+      nent = shdr[i].sh_size / sizeof(Elf32_Sym);
+      IF_DEBUG(linker,belch( "   number of entries is apparently %d (%d rem)",
+               nent,
+               shdr[i].sh_size % sizeof(Elf32_Sym)
+             ));
+      if (0 != shdr[i].sh_size % sizeof(Elf32_Sym)) {
+         belch("ocVerifyImage_ELF: non-integral number of symbol table entries");
+         return 0;
+      }
+      for (j = 0; j < nent; j++) {
+         IF_DEBUG(linker,fprintf(stderr, "   %2d  ", j ));
+         IF_DEBUG(linker,fprintf(stderr, "  sec=%-5d  size=%-3d  val=%5p  ", 
+                             (int)stab[j].st_shndx,
+                             (int)stab[j].st_size,
+                             (char*)stab[j].st_value ));
+
+         IF_DEBUG(linker,fprintf(stderr, "type=" ));
+         switch (ELF32_ST_TYPE(stab[j].st_info)) {
+            case STT_NOTYPE:  IF_DEBUG(linker,fprintf(stderr, "notype " )); break;
+            case STT_OBJECT:  IF_DEBUG(linker,fprintf(stderr, "object " )); break;
+            case STT_FUNC  :  IF_DEBUG(linker,fprintf(stderr, "func   " )); break;
+            case STT_SECTION: IF_DEBUG(linker,fprintf(stderr, "section" )); break;
+            case STT_FILE:    IF_DEBUG(linker,fprintf(stderr, "file   " )); break;
+            default:          IF_DEBUG(linker,fprintf(stderr, "?      " )); break;
+         }
+         IF_DEBUG(linker,fprintf(stderr, "  " ));
+
+         IF_DEBUG(linker,fprintf(stderr, "bind=" ));
+         switch (ELF32_ST_BIND(stab[j].st_info)) {
+            case STB_LOCAL :  IF_DEBUG(linker,fprintf(stderr, "local " )); break;
+            case STB_GLOBAL:  IF_DEBUG(linker,fprintf(stderr, "global" )); break;
+            case STB_WEAK  :  IF_DEBUG(linker,fprintf(stderr, "weak  " )); break;
+            default:          IF_DEBUG(linker,fprintf(stderr, "?     " )); break;
+         }
+         IF_DEBUG(linker,fprintf(stderr, "  " ));
+
+         IF_DEBUG(linker,fprintf(stderr, "name=%s\n", strtab + stab[j].st_name ));
+      }
+   }
+
+   if (nsymtabs == 0) {
+      belch("ocVerifyImage_ELF: didn't find any symbol tables");
+      return 0;
+   }
+
+   return 1;
+}
+
+
+static int
+ocGetNames_ELF ( ObjectCode* oc )
+{
+   int i, j, k, nent;
+   Elf32_Sym* stab;
+
+   char*       ehdrC      = (char*)(oc->image);
+   Elf32_Ehdr* ehdr       = (Elf32_Ehdr*)ehdrC;
+   char*       strtab     = findElfSection ( ehdrC, SHT_STRTAB );
+   Elf32_Shdr* shdr       = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
+   char*       sh_strtab  = ehdrC + shdr[ehdr->e_shstrndx].sh_offset;
+
+   if (!strtab) {
+      belch("ocGetNames_ELF: no strtab");
+      return 0;
+   }
+
+   k = 0;
+   oc->sections = stgMallocBytes( ehdr->e_shnum * sizeof(Section), 
+                                   "ocGetNames_ELF" );
+   oc->n_sections = ehdr->e_shnum;
+
+   for (i = 0; i < ehdr->e_shnum; i++) {
+
+      /* make a section entry for relevant sections */
+      SectionKind kind = SECTIONKIND_OTHER;
+      if (!strcmp(".data",sh_strtab+shdr[i].sh_name) ||
+          !strcmp(".data1",sh_strtab+shdr[i].sh_name))
+         kind = SECTIONKIND_RWDATA;
+      if (!strcmp(".text",sh_strtab+shdr[i].sh_name) ||
+          !strcmp(".rodata",sh_strtab+shdr[i].sh_name) ||
+          !strcmp(".rodata1",sh_strtab+shdr[i].sh_name))
+         kind = SECTIONKIND_CODE_OR_RODATA;
+
+      /* fill in the section info */
+      oc->sections[i].start = ehdrC + shdr[i].sh_offset;
+      oc->sections[i].end   = ehdrC + shdr[i].sh_offset + shdr[i].sh_size - 1;
+      oc->sections[i].kind  = kind;
+      
+      if (shdr[i].sh_type != SHT_SYMTAB) continue;
+
+      /* copy stuff into this module's object symbol table */
+      stab = (Elf32_Sym*) (ehdrC + shdr[i].sh_offset);
+      nent = shdr[i].sh_size / sizeof(Elf32_Sym);
+      oc->symbols = malloc(nent * sizeof(SymbolVal));
+      for (j = 0; j < nent; j++) {
+         if ( ( ELF32_ST_BIND(stab[j].st_info)==STB_GLOBAL /* ||
+               ELF32_ST_BIND(stab[j].st_info)==STB_LOCAL */
+              )
+             /* and not an undefined symbol */
+             && stab[j].st_shndx != SHN_UNDEF
+             &&
+             /* and it's a not a section or string table or anything silly */
+              ( ELF32_ST_TYPE(stab[j].st_info)==STT_FUNC ||
+                ELF32_ST_TYPE(stab[j].st_info)==STT_OBJECT ||
+               ELF32_ST_TYPE(stab[j].st_info)==STT_NOTYPE )
+               ) { 
+            char* nm = strtab + stab[j].st_name;
+            char* ad = ehdrC 
+                       + shdr[ stab[j].st_shndx ].sh_offset
+                       + stab[j].st_value;
+            ASSERT(nm != NULL);
+            ASSERT(ad != NULL);
+           IF_DEBUG(linker,belch( "addOTabName: %10p  %s %s",
+                       ad, oc->fileName, nm ));
+           oc->symbols[j].lbl  = nm;
+           oc->symbols[j].addr = ad;
+           insertStrHashTable(symhash, nm, &(oc->symbols[j]));
+         }
+        else {
+            IF_DEBUG(linker,belch( "skipping `%s'", strtab +
+                            stab[j].st_name ));
+            oc->symbols[j].lbl  = NULL;
+            oc->symbols[j].addr = NULL;
+        }
+      }
+   }
+
+   return 1;
+}
+
+
+static int
+ocResolve_ELF ( ObjectCode* oc )
+{
+   char *strtab, *symbol;
+   int   i, j;
+   Elf32_Sym*  stab = NULL;
+   char*       ehdrC = (char*)(oc->image);
+   Elf32_Ehdr* ehdr = (Elf32_Ehdr*) ehdrC;
+   Elf32_Shdr* shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
+   Elf32_Word* targ;
+
+   /* first find "the" symbol table */
+   stab = (Elf32_Sym*) findElfSection ( ehdrC, SHT_SYMTAB );
+
+   /* also go find the string table */
+   strtab = findElfSection ( ehdrC, SHT_STRTAB );
+
+   if (stab == NULL || strtab == NULL) {
+      belch("ocResolve_ELF: can't find string or symbol table");
+      return 0; 
+   }
+
+   for (i = 0; i < ehdr->e_shnum; i++) {
+      if (shdr[i].sh_type == SHT_REL ) {
+         Elf32_Rel*  rtab = (Elf32_Rel*) (ehdrC + shdr[i].sh_offset);
+         int         nent = shdr[i].sh_size / sizeof(Elf32_Rel);
+         int target_shndx = shdr[i].sh_info;
+         int symtab_shndx = shdr[i].sh_link;
+         stab  = (Elf32_Sym*) (ehdrC + shdr[ symtab_shndx ].sh_offset);
+         targ  = (Elf32_Word*)(ehdrC + shdr[ target_shndx ].sh_offset);
+        IF_DEBUG(linker,belch( "relocations for section %d using symtab %d",
+                        target_shndx, symtab_shndx ));
+         for (j = 0; j < nent; j++) {
+            Elf32_Addr offset = rtab[j].r_offset;
+            Elf32_Word info   = rtab[j].r_info;
+
+            Elf32_Addr  P = ((Elf32_Addr)targ) + offset;
+            Elf32_Word* pP = (Elf32_Word*)P;
+            Elf32_Addr  A = *pP;
+            Elf32_Addr  S;
+
+            IF_DEBUG(linker,belch( "Rel entry %3d is raw(%6p %6p)   ", 
+                                j, (void*)offset, (void*)info ));
+            if (!info) {
+               IF_DEBUG(linker,belch( " ZERO" ));
+               S = 0;
+            } else {
+               /* First see if it is a nameless local symbol. */
+               if (stab[ ELF32_R_SYM(info)].st_name == 0) {
+                  symbol = "(noname)";
+                  S = (Elf32_Addr)(ehdrC
+                                   + shdr[stab[ELF32_R_SYM(info)].st_shndx ].sh_offset
+                                   + stab[ELF32_R_SYM(info)].st_value
+                      );
+               } else {
+                  /* No?  Should be in the symbol table then. */
+                  symbol = strtab+stab[ ELF32_R_SYM(info)].st_name;
+                  (void *)S = lookupSymbol( symbol );
+               }
+               if (!S) {
+                  barf("ocResolve_ELF: %s: unknown symbol `%s'",
+                       oc->fileName, symbol);
+               }
+               IF_DEBUG(linker,belch( "`%s' resolves to %p", symbol, (void*)S ));
+           }
+            IF_DEBUG(linker,fprintf ( stderr, "Reloc: P = %p   S = %p   A = %p\n", (void*)P, (void*)S, (void*)A )); 
+            switch (ELF32_R_TYPE(info)) {
+               case R_386_32:   *pP = S + A;     break;
+               case R_386_PC32: *pP = S + A - P; break;
+               default: fprintf(stderr, 
+                                "unhandled ELF relocation type %d",
+                                ELF32_R_TYPE(info));
+                        belch("ocResolve_ELF: unhandled ELF relocation type");
+                        return 0;
+           }
+
+         }
+      }
+      else
+      if (shdr[i].sh_type == SHT_RELA) {
+         belch("ocResolve_ELF: RelA style reloc table -- not yet done");
+         return 0;
+      }
+   }
+
+   return 1;
+}
+
+
+#endif /* defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS) */
+
+/* -----------------------------------------------------------------------------
+ * Look up an address to discover whether it is in text or data space.
+ *
+ * Used by the garbage collector when walking the stack.
+ * -------------------------------------------------------------------------- */
+
+SectionKind
+lookupSection ( void* addr )
+{
+   int          i;
+   ObjectCode*  oc;
+   
+   for ( oc = objects; oc; oc = oc->next ) {
+       for (i = 0; i < oc->n_sections; i++) {
+          if (oc->sections[i].start <= addr 
+              && addr <= oc->sections[i].end)
+              return oc->sections[i].kind;
+       }
+   }
+   return SECTIONKIND_OTHER;
+}
+
+int
+is_dynamically_loaded_code_or_rodata_ptr ( char* p )
+{
+   SectionKind sk = lookupSection(p);
+   assert (sk != SECTIONKIND_NOINFOAVAIL);
+   return (sk == SECTIONKIND_CODE_OR_RODATA);
+}
+
+
+int
+is_dynamically_loaded_rwdata_ptr ( char* p )
+{
+   SectionKind sk = lookupSection(p);
+   assert (sk != SECTIONKIND_NOINFOAVAIL);
+   return (sk == SECTIONKIND_RWDATA);
+}
+
+
+int
+is_not_dynamically_loaded_ptr ( char* p )
+{
+   SectionKind sk = lookupSection(p);
+   assert (sk != SECTIONKIND_NOINFOAVAIL);
+   return (sk == SECTIONKIND_OTHER);
+}
+
diff --git a/ghc/rts/Linker.h b/ghc/rts/Linker.h
new file mode 100644 (file)
index 0000000..d4b723e
--- /dev/null
@@ -0,0 +1,29 @@
+/* -----------------------------------------------------------------------------
+ * $Id: Linker.h,v 1.1 2000/10/06 15:33:27 simonmar Exp $
+ *
+ * (c) The GHC Team, 2000
+ *
+ * RTS Object Linker
+ *
+ * ---------------------------------------------------------------------------*/
+
+/* initialize the object linker */
+void initLinker( void );
+
+/* lookup a symbol in the hash table */
+void *lookupSymbol( char *lbl );
+
+/* delete an object from the pool */
+HsInt unloadObj( char *path );
+
+/* add an obj (populate the global symbol table, but don't resolve yet) */
+HsInt loadObj( char *path );
+
+/* resolve all the currently unlinked objects in memory */
+HsInt resolveObjs( void );
+
+/* These three are used by the garbage collector (see ClosureMacros.h,
+   IS_CODE_PTR etc.). */
+int is_dynamically_loaded_code_or_rodata_ptr ( char* p );
+int is_dynamically_loaded_rwdata_ptr ( char* p );
+int is_not_dynamically_loaded_ptr ( char* p );