[project @ 2001-02-14 11:36:07 by sewardj]
[ghc-hetmet.git] / ghc / rts / Linker.c
index fa60810..d76e042 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: Linker.c,v 1.3 2000/12/12 12:19:57 simonmar Exp $
+ * $Id: Linker.c,v 1.29 2001/02/14 11:02:36 sewardj Exp $
  *
  * (c) The GHC Team, 2000
  *
 #include "HsFFI.h"
 #include "Hash.h"
 #include "Linker.h"
+#include "LinkerInternals.h"
 #include "RtsUtils.h"
+#include "StoragePriv.h"
 
-/* These two are POSIX headers */
+#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
+#endif
 
-/* ToDo: configure this */
+#ifdef HAVE_DLFCN_H
 #include <dlfcn.h>
+#endif
 
-/* 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;
-
+#if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS) || defined(freebsd_TARGET_OS)
+#define OBJFORMAT_ELF
+#elif defined(cygwin32_TARGET_OS) || defined (mingw32_TARGET_OS)
+#define OBJFORMAT_PEi386
+#endif
 
 /* 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)
+#if defined(OBJFORMAT_ELF)
 static int ocVerifyImage_ELF    ( ObjectCode* oc );
 static int ocGetNames_ELF       ( ObjectCode* oc );
 static int ocResolve_ELF        ( ObjectCode* oc );
-#elif defined(cygwin32_TARGET_OS)              
+#elif defined(OBJFORMAT_PEi386)
 static int ocVerifyImage_PEi386 ( ObjectCode* oc );
 static int ocGetNames_PEi386    ( ObjectCode* oc );
 static int ocResolve_PEi386     ( ObjectCode* oc );
@@ -125,22 +86,28 @@ static int ocResolve_PEi386     ( ObjectCode* oc );
       SymX(stg_sel_10_upd_info)                        \
       SymX(stg_sel_11_upd_info)                        \
       SymX(stg_sel_12_upd_info)                        \
+      SymX(stg_sel_13_upd_info)                        \
+      SymX(stg_sel_14_upd_info)                        \
+      SymX(stg_sel_15_upd_info)                        \
       SymX(stg_upd_frame_info)                 \
       SymX(stg_seq_frame_info)                 \
       SymX(stg_CAF_BLACKHOLE_info)             \
       SymX(stg_IND_STATIC_info)                        \
       SymX(stg_EMPTY_MVAR_info)                        \
       SymX(stg_MUT_ARR_PTRS_FROZEN_info)       \
+      SymX(stg_WEAK_info)                       \
       SymX(stg_CHARLIKE_closure)               \
       SymX(stg_INTLIKE_closure)                        \
-      SymX(stg_CAF_UNENTERED_entry)            \
       SymX(newCAF)                             \
+      SymX(newBCOzh_fast)                      \
+      SymX(mkApUpd0zh_fast)                    \
       SymX(putMVarzh_fast)                     \
       SymX(newMVarzh_fast)                     \
       SymX(takeMVarzh_fast)                    \
       SymX(tryTakeMVarzh_fast)                 \
       SymX(catchzh_fast)                       \
       SymX(raisezh_fast)                       \
+      SymX(forkzh_fast)                                \
       SymX(delayzh_fast)                       \
       SymX(yieldzh_fast)                       \
       SymX(killThreadzh_fast)                  \
@@ -150,25 +117,11 @@ static int ocResolve_PEi386     ( ObjectCode* oc );
       SymX(resumeThread)                       \
       SymX(stackOverflow)                      \
       SymX(int2Integerzh_fast)                 \
-      SymX(ErrorHdrHook)                       \
+      SymX(word2Integerzh_fast)                        \
       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)             \
@@ -182,7 +135,30 @@ static int ocResolve_PEi386     ( ObjectCode* oc );
       SymX(timesIntegerzh_fast)                        \
       SymX(minusIntegerzh_fast)                        \
       SymX(plusIntegerzh_fast)                 \
+      SymX(andIntegerzh_fast)                  \
+      SymX(orIntegerzh_fast)                   \
+      SymX(xorIntegerzh_fast)                  \
+      SymX(complementIntegerzh_fast)           \
       SymX(mkWeakzh_fast)                      \
+      SymX(makeStableNamezh_fast)              \
+      SymX(finalizzeWeakzh_fast)               \
+      SymX(blockAsyncExceptionszh_fast)                \
+      SymX(unblockAsyncExceptionszh_fast)      \
+      SymX(isDoubleNaN)                                \
+      SymX(isDoubleInfinite)                   \
+      SymX(isDoubleDenormalized)               \
+      SymX(isDoubleNegativeZero)               \
+      SymX(__encodeFloat)                      \
+      SymX(isFloatNaN)                         \
+      SymX(isFloatInfinite)                    \
+      SymX(isFloatDenormalized)                        \
+      SymX(isFloatNegativeZero)                        \
+      SymX(__int_encodeFloat)                  \
+      SymX(__int_encodeDouble)                 \
+      SymX(__gmpz_cmp_si)                      \
+      SymX(__gmpz_cmp_ui)                      \
+      SymX(__gmpz_cmp)                         \
+      SymX(__gmpn_gcd_1)                       \
       SymX(prog_argv)                          \
       SymX(prog_argc)                          \
       SymX(resetNonBlockingFd)                 \
@@ -190,12 +166,74 @@ static int ocResolve_PEi386     ( ObjectCode* oc );
       SymX(stable_ptr_table)                   \
       SymX(shutdownHaskellAndExit)             \
       Sym(stg_enterStackTop)                   \
-      Sym(stg_yield_to_Hugs)                   \
+      Sym(stg_yield_to_interpreter)            \
       Sym(StgReturn)                           \
       Sym(init_stack)                          \
-      SymX(blockAsyncExceptionszh_fast)                \
-      SymX(unblockAsyncExceptionszh_fast)      \
-      Sym(__init_PrelGHC)
+      SymX(cmp_thread)                         \
+      Sym(__init_PrelGHC)                      \
+      SymX(freeHaskellFunctionPtr)             \
+      SymX(OnExitHook)                         \
+      SymX(ErrorHdrHook)                       \
+      SymX(NoRunnableThreadsHook)              \
+      SymX(StackOverflowHook)                  \
+      SymX(OutOfHeapHook)                      \
+      SymX(MallocFailHook)                     \
+      SymX(PatErrorHdrHook)                    \
+      SymX(defaultsHook)                       \
+      SymX(PreTraceHook)                       \
+      SymX(PostTraceHook)                      \
+      SymX(stg_sig_install)                    \
+      Sym(nocldstop)                           \
+      SymX(createAdjustor)                     \
+      SymX(rts_mkInt)                          \
+      SymX(rts_mkStablePtr)                    \
+      SymX(rts_apply)                          \
+      SymX(rts_evalIO)                         \
+      SymX(rts_checkSchedStatus)               \
+      SymX(rts_getInt)
+
+#ifndef SUPPORT_LONG_LONGS
+#define RTS_LONG_LONG_SYMS /* nothing */
+#else
+#define RTS_LONG_LONG_SYMS \
+      SymX(stg_gtWord64)                       \
+      SymX(stg_geWord64)                       \
+      SymX(stg_eqWord64)                       \
+      SymX(stg_neWord64)                       \
+      SymX(stg_ltWord64)                       \
+      SymX(stg_leWord64)                       \
+      SymX(stg_gtInt64)                                \
+      SymX(stg_geInt64)                                \
+      SymX(stg_eqInt64)                                \
+      SymX(stg_neInt64)                                \
+      SymX(stg_ltInt64)                                \
+      SymX(stg_leInt64)                                \
+      SymX(stg_remWord64)                      \
+      SymX(stg_quotWord64)                     \
+      SymX(stg_remInt64)                       \
+      SymX(stg_quotInt64)                      \
+      SymX(stg_negateInt64)                    \
+      SymX(stg_plusInt64)                      \
+      SymX(stg_minusInt64)                     \
+      SymX(stg_timesInt64)                     \
+      SymX(stg_and64)                          \
+      SymX(stg_or64)                           \
+      SymX(stg_xor64)                          \
+      SymX(stg_not64)                          \
+      SymX(stg_shiftL64)                       \
+      SymX(stg_shiftRL64)                      \
+      SymX(stg_iShiftL64)                      \
+      SymX(stg_iShiftRL64)                     \
+      SymX(stg_iShiftRA64)                     \
+      SymX(stg_intToInt64)                     \
+      SymX(stg_int64ToInt)                     \
+      SymX(stg_int64ToWord64)                  \
+      SymX(stg_wordToWord64)                   \
+      SymX(stg_word64ToWord)                   \
+      SymX(stg_word64ToInt64)                  \
+      SymX(int64ToIntegerzh_fast)              \
+      SymX(word64ToIntegerzh_fast)
+#endif /* SUPPORT_LONG_LONGS */
 
 /* entirely bogus claims about types of these symbols */
 #define Sym(vvv)  extern void (vvv);
@@ -216,6 +254,7 @@ RTS_SYMBOLS
 
 static SymbolVal rtsSyms[] = {
       RTS_SYMBOLS
+      RTS_LONG_LONG_SYMS
       { 0, 0 } /* sentinel */
 };
 
@@ -240,12 +279,49 @@ initLinker( void )
 }
 
 /* -----------------------------------------------------------------------------
+ * Add a DLL from which symbols may be found.  In the ELF case, just
+ * do RTLD_GLOBAL-style add, so no further messing around needs to
+ * happen in order that symbols in the loaded .so are findable --
+ * lookupSymbol() will subsequently see them by dlsym on the program's
+ * dl-handle.  Returns 0 if fail, 1 if success.
+ */
+char*
+addDLL ( char* dll_name )
+{
+#  if defined(OBJFORMAT_ELF)
+   void *hdl;
+   char *buf;
+   char *errmsg;
+
+   buf = stgMallocBytes(strlen(dll_name) + 10, "addDll");
+   sprintf(buf, "lib%s.so", dll_name);
+   hdl = dlopen(buf, RTLD_NOW | RTLD_GLOBAL );
+   free(buf);
+   if (hdl == NULL) {
+      /* dlopen failed; return a ptr to the error msg. */
+      errmsg = dlerror();
+      if (errmsg == NULL) errmsg = "addDLL: unknown error";
+      return errmsg;
+   } else {
+      return NULL;
+   }
+   ASSERT(0); /*NOTREACHED*/
+#  elif defined(OBJFORMAT_PEi386)
+   barf("addDLL: not implemented on PEi386 yet");
+   return 0;
+#  else
+   barf("addDLL: not implemented on this platform");
+#  endif
+}
+
+/* -----------------------------------------------------------------------------
  * lookup a symbol in the hash table
  */  
 void *
 lookupSymbol( char *lbl )
 {
     SymbolVal *val;
+    ASSERT(symhash != NULL);
     val = lookupStrHashTable(symhash, lbl);
 
     if (val == NULL) {
@@ -255,6 +331,21 @@ lookupSymbol( char *lbl )
     }
 }
 
+static 
+void *
+lookupLocalSymbol( ObjectCode* oc, char *lbl )
+{
+    SymbolVal *val;
+    val = lookupStrHashTable(oc->lochash, lbl);
+
+    if (val == NULL) {
+        return NULL;
+    } else {
+       return val->addr;
+    }
+}
+
+
 /* -----------------------------------------------------------------------------
  * Load an obj (populate the global symbol table, but don't resolve yet)
  *
@@ -268,20 +359,20 @@ loadObj( char *path )
    int r, n;
    FILE *f;
 
-#ifdef DEBUG
+#  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 */   
+#  endif /* DEBUG */   
 
    oc = stgMallocBytes(sizeof(ObjectCode), "loadObj(oc)");
 
-#  if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
+#  if defined(OBJFORMAT_ELF)
    oc->formatName = "ELF";
-#  elif defined(cygwin32_TARGET_OS)
+#  elif defined(OBJFORMAT_PEi386)
    oc->formatName = "PEi386";
 #  else
    free(oc);
@@ -291,11 +382,15 @@ loadObj( char *path )
    r = stat(path, &st);
    if (r == -1) { return 0; }
 
-   oc->fileName          = path;
+   /* sigh, strdup() isn't a POSIX function, so do it the long way */
+   oc->fileName = stgMallocBytes( strlen(path)+1, "loadObj" );
+   strcpy(oc->fileName, path);
+
    oc->fileSize          = st.st_size;
    oc->image             = stgMallocBytes( st.st_size, "loadObj(image)" );
    oc->symbols           = NULL;
    oc->sections          = NULL;
+   oc->lochash           = allocStrHashTable();
 
    /* chain it onto the list of objects */
    oc->next              = objects;
@@ -313,9 +408,9 @@ loadObj( char *path )
    }
 
    /* verify the in-memory image */
-#  if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
+#  if defined(OBJFORMAT_ELF)
    r = ocVerifyImage_ELF ( oc );
-#  elif defined(cygwin32_TARGET_OS)
+#  elif defined(OBJFORMAT_PEi386)
    r = ocVerifyImage_PEi386 ( oc );
 #  else
    barf("loadObj: no verify method");
@@ -323,9 +418,9 @@ loadObj( char *path )
    if (!r) { return r; }
 
    /* build the symbol list for this image */
-#  if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
+#  if defined(OBJFORMAT_ELF)
    r = ocGetNames_ELF ( oc );
-#  elif defined(cygwin32_TARGET_OS)
+#  elif defined(OBJFORMAT_PEi386)
    r = ocGetNames_PEi386 ( oc );
 #  else
    barf("loadObj: no getNames method");
@@ -351,13 +446,13 @@ resolveObjs( void )
 
     for (oc = objects; oc; oc = oc->next) {
        if (oc->status != OBJECT_RESOLVED) {
-#  if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
+#           if defined(OBJFORMAT_ELF)
            r = ocResolve_ELF ( oc );
-#  elif defined(cygwin32_TARGET_OS)
+#           elif defined(OBJFORMAT_PEi386)
            r = ocResolve_PEi386 ( oc );
-#  else
+#           else
            barf("link: not implemented on this platform");
-#  endif
+#           endif
            if (!r) { return r; }
            oc->status = OBJECT_RESOLVED;
        }
@@ -371,9 +466,13 @@ resolveObjs( void )
 HsInt
 unloadObj( char *path )
 {
-    ObjectCode *oc;
+    ObjectCode *oc, *prev;
 
-    for (oc = objects; oc; oc = oc->next) {
+    ASSERT(symhash != NULL);
+    ASSERT(objects != NULL);
+
+    prev = NULL;
+    for (oc = objects; oc; prev = oc, oc = oc->next) {
        if (!strcmp(oc->fileName,path)) {
 
            /* Remove all the mappings for the symbols within this
@@ -382,26 +481,38 @@ unloadObj( char *path )
            { 
                SymbolVal *s;
                for (s = oc->symbols; s < oc->symbols + oc->n_symbols; s++) {
-                   removeStrHashTable(symhash, s->lbl, NULL);
+                   if (s->lbl != NULL) {
+                       removeStrHashTable(symhash, s->lbl, NULL);
+                   }
                }
            }
 
+           if (prev == NULL) {
+               objects = oc->next;
+           } else {
+               prev->next = oc->next;
+           }
+
            /* We're going to leave this in place, in case there are
               any pointers from the heap into it: */
            /* free(oc->image); */
+           free(oc->fileName);
            free(oc->symbols);
            free(oc->sections);
+           /* The local hash table should have been freed at the end
+               of the ocResolve_ call on it. */
+            ASSERT(oc->lochash == NULL);
            free(oc);
            return 1;
        }
     }
-    
+
     belch("unloadObj: can't find `%s' to unload", path);
     return 0;
 }
 
 /* --------------------------------------------------------------------------
- * PEi386 specifics (cygwin32)
+ * PEi386 specifics (Win32 targets)
  * ------------------------------------------------------------------------*/
 
 /* The information for this linker comes from 
@@ -412,7 +523,7 @@ unloadObj( char *path )
 */
       
 
-#if defined(cygwin32_TARGET_OS)
+#if defined(OBJFORMAT_PEi386)
 
 
 
@@ -1026,18 +1137,22 @@ ocResolve_PEi386 ( ObjectCode* oc, int verb )
    return TRUE;
 }
 
-#endif /* defined(cygwin32_TARGET_OS) */
+#endif /* defined(OBJFORMAT_PEi386) */
 
 
 /* --------------------------------------------------------------------------
- * ELF specifics (Linux, Solaris)
+ * ELF specifics
  * ------------------------------------------------------------------------*/
 
-#if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS)
+#if defined(OBJFORMAT_ELF)
 
 #define FALSE 0
 #define TRUE  1
 
+#if defined(sparc_TARGET_ARCH)
+#  define ELF_TARGET_SPARC  /* Used inside <elf.h> */
+#endif
+
 #include <elf.h>
 
 static char *
@@ -1131,9 +1246,9 @@ ocVerifyImage_ELF ( ObjectCode* oc )
 
    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, "type=%2d  ", (int)shdr[i].sh_type ));
+      IF_DEBUG(linker,fprintf(stderr, "size=%4d  ", (int)shdr[i].sh_size ));
+      IF_DEBUG(linker,fprintf(stderr, "offs=%4d  ", (int)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));
@@ -1234,6 +1349,8 @@ ocGetNames_ELF ( ObjectCode* oc )
    Elf32_Shdr* shdr       = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
    char*       sh_strtab  = ehdrC + shdr[ehdr->e_shstrndx].sh_offset;
 
+   ASSERT(symhash != NULL);
+
    if (!strtab) {
       belch("ocGetNames_ELF: no strtab");
       return 0;
@@ -1267,33 +1384,52 @@ ocGetNames_ELF ( ObjectCode* oc )
       stab = (Elf32_Sym*) (ehdrC + shdr[i].sh_offset);
       nent = shdr[i].sh_size / sizeof(Elf32_Sym);
       oc->symbols = malloc(nent * sizeof(SymbolVal));
+      oc->n_symbols = nent;
       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 */
+         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 not an undefined symbol */
+              && stab[j].st_shndx != SHN_UNDEF
+             /* and not in a "special section" */
+              && stab[j].st_shndx < SHN_LORESERVE
+              &&
              /* 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 )
-               ) { 
+                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]));
+            if (ELF32_ST_BIND(stab[j].st_info)==STB_LOCAL) {
+               IF_DEBUG(linker,belch( "addOTabName(LOCL): %10p  %s %s",
+                                      ad, oc->fileName, nm ));
+               insertStrHashTable(oc->lochash, nm, &(oc->symbols[j]));
+            } else {
+               IF_DEBUG(linker,belch( "addOTabName(GLOB): %10p  %s %s",
+                                      ad, oc->fileName, nm ));
+               insertStrHashTable(symhash, nm, &(oc->symbols[j]));
+            }
          }
         else {
-            IF_DEBUG(linker,belch( "skipping `%s'", strtab +
-                            stab[j].st_name ));
+            IF_DEBUG(linker,belch( "skipping `%s'", 
+                                    strtab + stab[j].st_name ));
+            /*
+            fprintf(stderr, 
+                    "skipping   bind = %d,  type = %d,  shndx = %d   `%s'\n",
+                    (int)ELF32_ST_BIND(stab[j].st_info), 
+                     (int)ELF32_ST_TYPE(stab[j].st_info), 
+                     (int)stab[j].st_shndx,
+                     strtab + stab[j].st_name
+                    );
+            */
             oc->symbols[j].lbl  = NULL;
             oc->symbols[j].addr = NULL;
         }
@@ -1304,16 +1440,188 @@ ocGetNames_ELF ( ObjectCode* oc )
 }
 
 
+/* Do ELF relocations which lack an explicit addend.  All x86-linux
+   relocations appear to be of this form. */
+static int do_Elf32_Rel_relocations ( ObjectCode* oc, char* ehdrC,
+                                      Elf32_Shdr* shdr, int shnum, 
+                                      Elf32_Sym*  stab, char* strtab )
+{
+   int j;
+   char *symbol;
+   Elf32_Word* targ;
+   Elf32_Rel*  rtab = (Elf32_Rel*) (ehdrC + shdr[shnum].sh_offset);
+   int         nent = shdr[shnum].sh_size / sizeof(Elf32_Rel);
+   int target_shndx = shdr[shnum].sh_info;
+   int symtab_shndx = shdr[shnum].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 a symbol table then; first try the
+               local one. */
+            symbol = strtab+stab[ ELF32_R_SYM(info)].st_name;
+            (void*)S = lookupLocalSymbol( oc, symbol );
+            if ((void*)S == NULL)
+               (void*)S = lookupSymbol( symbol );
+         }
+         if (!S) {
+            barf("do_Elf32_Rel_relocations:  %s: unknown symbol `%s'", 
+                 oc->fileName, symbol);
+         }
+         IF_DEBUG(linker,belch( "`%s' resolves to %p", symbol, (void*)S ));
+      }
+      IF_DEBUG(linker,belch( "Reloc: P = %p   S = %p   A = %p",
+                            (void*)P, (void*)S, (void*)A )); 
+      switch (ELF32_R_TYPE(info)) {
+#ifdef i386_TARGET_ARCH
+         case R_386_32:   *pP = S + A;     break;
+         case R_386_PC32: *pP = S + A - P; break;
+#endif
+         default: 
+            barf("do_Elf32_Rel_relocations: unhandled ELF relocation(Rel) type %d\n", ELF32_R_TYPE(info));
+            return 0;
+      }
+
+   }
+   return 1;
+}
+
+
+/* Do ELF relocations for which explicit addends are supplied.
+   sparc-solaris relocations appear to be of this form. */
+static int do_Elf32_Rela_relocations ( ObjectCode* oc, char* ehdrC,
+                                       Elf32_Shdr* shdr, int shnum, 
+                                       Elf32_Sym*  stab, char* strtab )
+{
+   int j;
+   char *symbol;
+   Elf32_Word* targ;
+   Elf32_Rela* rtab = (Elf32_Rela*) (ehdrC + shdr[shnum].sh_offset);
+   int         nent = shdr[shnum].sh_size / sizeof(Elf32_Rela);
+   int target_shndx = shdr[shnum].sh_info;
+   int symtab_shndx = shdr[shnum].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_Sword addend = rtab[j].r_addend;
+
+      Elf32_Addr  P  = ((Elf32_Addr)targ) + offset;
+      Elf32_Addr  A  = addend;
+      Elf32_Addr  S;
+#     if defined(sparc_TARGET_ARCH)
+      /* This #ifdef only serves to avoid unused-var warnings. */
+      Elf32_Word* pP = (Elf32_Word*)P;
+      Elf32_Word  w1, w2;
+#     endif
+
+      IF_DEBUG(linker,belch( "Rel entry %3d is raw(%6p %6p %6p)   ", 
+                             j, (void*)offset, (void*)info, 
+                                (void*)addend ));
+      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 a symbol table then; first try the
+               local one. */
+            symbol = strtab+stab[ ELF32_R_SYM(info)].st_name;
+            (void*)S = lookupLocalSymbol( oc, symbol );
+            if ((void*)S == NULL)
+               (void*)S = lookupSymbol( symbol );
+         }
+         if (!S) {
+          barf("ocResolve_ELF: %s: unknown symbol `%s'", 
+                   oc->fileName, symbol);
+          /* 
+          S = 0x11223344;
+          fprintf ( stderr, "S %p A %p S+A %p S+A-P %p\n",S,A,S+A,S+A-P);
+          */
+         }
+         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)) {
+#        if defined(sparc_TARGET_ARCH)
+         case R_SPARC_WDISP30: 
+            w1 = *pP & 0xC0000000;
+            w2 = (Elf32_Word)((S + A - P) >> 2);
+            ASSERT((w2 & 0xC0000000) == 0);
+            w1 |= w2;
+            *pP = w1;
+            break;
+         case R_SPARC_HI22:
+            w1 = *pP & 0xFFC00000;
+            w2 = (Elf32_Word)((S + A) >> 10);
+            ASSERT((w2 & 0xFFC00000) == 0);
+            w1 |= w2;
+            *pP = w1;
+            break;
+         case R_SPARC_LO10:
+            w1 = *pP & ~0x3FF;
+            w2 = (Elf32_Word)((S + A) & 0x3FF);
+            ASSERT((w2 & ~0x3FF) == 0);
+            w1 |= w2;
+            *pP = w1;
+            break;
+         case R_SPARC_32:
+            w2 = (Elf32_Word)(S + A);
+            *pP = w2;
+            break;
+#        endif
+         default: 
+            fprintf(stderr, "unhandled ELF relocation(RelA) type %d\n",
+                            ELF32_R_TYPE(info));
+            barf("do_Elf32_Rela_relocations: unhandled ELF relocation type");
+            return 0;
+      }
+
+   }
+   return 1;
+}
+
+
 static int
 ocResolve_ELF ( ObjectCode* oc )
 {
-   char *strtab, *symbol;
-   int   i, j;
+   char *strtab;
+   int   shnum, ok;
    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 );
@@ -1326,120 +1634,27 @@ ocResolve_ELF ( ObjectCode* oc )
       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;
-           }
-
-         }
+   /* Process the relocation sections. */
+   for (shnum = 0; shnum < ehdr->e_shnum; shnum++) {
+      if (shdr[shnum].sh_type == SHT_REL ) {
+         ok = do_Elf32_Rel_relocations ( oc, ehdrC, shdr, 
+                                         shnum, stab, strtab );
+         if (!ok) return ok;
       }
       else
-      if (shdr[i].sh_type == SHT_RELA) {
-         belch("ocResolve_ELF: RelA style reloc table -- not yet done");
-         return 0;
+      if (shdr[shnum].sh_type == SHT_RELA) {
+         ok = do_Elf32_Rela_relocations ( oc, ehdrC, shdr, 
+                                          shnum, stab, strtab );
+         if (!ok) return ok;
       }
    }
 
-   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);
-}
+   /* Free the local symbol table; we won't need it again. */
+   freeHashTable(oc->lochash, NULL);
+   oc->lochash = NULL;
 
-
-int
-is_dynamically_loaded_rwdata_ptr ( char* p )
-{
-   SectionKind sk = lookupSection(p);
-   assert (sk != SECTIONKIND_NOINFOAVAIL);
-   return (sk == SECTIONKIND_RWDATA);
+   return 1;
 }
 
 
-int
-is_not_dynamically_loaded_ptr ( char* p )
-{
-   SectionKind sk = lookupSection(p);
-   assert (sk != SECTIONKIND_NOINFOAVAIL);
-   return (sk == SECTIONKIND_OTHER);
-}
-
+#endif /* ELF */