[project @ 2002-04-23 17:33:54 by ken]
[ghc-hetmet.git] / ghc / rts / Linker.c
index a45dc68..29dafaf 100644 (file)
@@ -1,12 +1,13 @@
 /* -----------------------------------------------------------------------------
 /* -----------------------------------------------------------------------------
- * $Id: Linker.c,v 1.46 2001/06/27 13:56:01 sewardj Exp $
+ * $Id: Linker.c,v 1.88 2002/04/23 17:33:54 ken Exp $
  *
  *
- * (c) The GHC Team, 2000
+ * (c) The GHC Team, 2000, 2001
  *
  * RTS Object Linker
  *
  * ---------------------------------------------------------------------------*/
 
  *
  * RTS Object Linker
  *
  * ---------------------------------------------------------------------------*/
 
+#include "PosixSource.h"
 #include "Rts.h"
 #include "RtsFlags.h"
 #include "HsFFI.h"
 #include "Rts.h"
 #include "RtsFlags.h"
 #include "HsFFI.h"
@@ -15,6 +16,7 @@
 #include "LinkerInternals.h"
 #include "RtsUtils.h"
 #include "StoragePriv.h"
 #include "LinkerInternals.h"
 #include "RtsUtils.h"
 #include "StoragePriv.h"
+#include "Schedule.h"
 
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
 
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
@@ -84,6 +86,39 @@ typedef struct _RtsSymbolVal {
 /* These are statically linked from the mingw libraries into the ghc
    executable, so we have to employ this hack. */
 #define RTS_MINGW_ONLY_SYMBOLS                  \
 /* These are statically linked from the mingw libraries into the ghc
    executable, so we have to employ this hack. */
 #define RTS_MINGW_ONLY_SYMBOLS                  \
+      SymX(memset)                              \
+      SymX(inet_ntoa)                           \
+      SymX(inet_addr)                           \
+      SymX(htonl)                               \
+      SymX(recvfrom)                            \
+      SymX(listen)                              \
+      SymX(bind)                                \
+      SymX(shutdown)                            \
+      SymX(connect)                             \
+      SymX(htons)                               \
+      SymX(ntohs)                               \
+      SymX(getservbyname)                       \
+      SymX(getservbyport)                       \
+      SymX(getprotobynumber)                    \
+      SymX(getprotobyname)                      \
+      SymX(gethostbyname)                       \
+      SymX(gethostbyaddr)                       \
+      SymX(gethostname)                         \
+      SymX(strcpy)                              \
+      SymX(strncpy)                             \
+      SymX(abort)                               \
+      Sym(_alloca)                              \
+      Sym(isxdigit)                             \
+      Sym(isupper)                              \
+      Sym(ispunct)                              \
+      Sym(islower)                              \
+      Sym(isspace)                              \
+      Sym(isprint)                              \
+      Sym(isdigit)                              \
+      Sym(iscntrl)                              \
+      Sym(isalpha)                              \
+      Sym(isalnum)                              \
+      SymX(strcmp)                              \
       SymX(memmove)                             \
       SymX(realloc)                             \
       SymX(malloc)                              \
       SymX(memmove)                             \
       SymX(realloc)                             \
       SymX(malloc)                              \
@@ -104,40 +139,176 @@ typedef struct _RtsSymbolVal {
       Sym(mktime)                               \
       Sym(_imp___timezone)                      \
       Sym(_imp___tzname)                        \
       Sym(mktime)                               \
       Sym(_imp___timezone)                      \
       Sym(_imp___tzname)                        \
+      Sym(_imp___iob)                           \
       Sym(localtime)                            \
       Sym(gmtime)                               \
       Sym(localtime)                            \
       Sym(gmtime)                               \
-      SymX(getenv)                              \
-      SymX(free)                                \
-      SymX(rename)                              \
       Sym(opendir)                              \
       Sym(readdir)                              \
       Sym(opendir)                              \
       Sym(readdir)                              \
+      Sym(rewinddir)                            \
       Sym(closedir)                             \
       Sym(closedir)                             \
-      SymX(GetCurrentProcess)                   \
-      SymX(GetProcessTimes)                     \
-      SymX(CloseHandle)                         \
-      SymX(GetExitCodeProcess)                  \
-      SymX(WaitForSingleObject)                 \
-      SymX(CreateProcessA)                      \
-      SymX(_errno)
+      Sym(__divdi3)                             \
+      Sym(__udivdi3)                            \
+      Sym(__moddi3)                             \
+      Sym(__umoddi3)
 #endif
 
 #endif
 
+#ifndef SMP
+# define MAIN_CAP_SYM SymX(MainCapability)
+#else
+# define MAIN_CAP_SYM
+#endif
 
 #define RTS_SYMBOLS                            \
 
 #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_unpt_r1)                      \
-      Sym(stg_gc_unbx_r1)                      \
-      Sym(stg_chk_0)                           \
-      Sym(stg_chk_1)                           \
-      Sym(stg_gen_chk)                         \
-      SymX(stg_exit)                           \
-      SymX(stg_update_PAP)                     \
+      Maybe_ForeignObj                         \
+      Maybe_Stable_Names                       \
+      Sym(StgReturn)                           \
+      Sym(__stginit_GHCziPrim)                 \
+      Sym(init_stack)                          \
+      SymX(__stg_chk_0)                                \
+      SymX(__stg_chk_1)                                \
+      Sym(stg_enterStackTop)                   \
+      SymX(stg_gc_d1)                          \
+      SymX(stg_gc_l1)                          \
+      SymX(__stg_gc_enter_1)                   \
+      SymX(stg_gc_f1)                          \
+      SymX(stg_gc_noregs)                      \
+      SymX(stg_gc_seq_1)                       \
+      SymX(stg_gc_unbx_r1)                     \
+      SymX(stg_gc_unpt_r1)                     \
+      SymX(stg_gc_ut_0_1)                      \
+      SymX(stg_gc_ut_1_0)                      \
+      SymX(stg_gen_chk)                                \
+      SymX(stg_yield_to_interpreter)           \
+      SymX(ErrorHdrHook)                       \
+      MAIN_CAP_SYM                              \
+      SymX(MallocFailHook)                     \
+      SymX(NoRunnableThreadsHook)              \
+      SymX(OnExitHook)                         \
+      SymX(OutOfHeapHook)                      \
+      SymX(PatErrorHdrHook)                    \
+      SymX(PostTraceHook)                      \
+      SymX(PreTraceHook)                       \
+      SymX(StackOverflowHook)                  \
+      SymX(__encodeDouble)                     \
+      SymX(__encodeFloat)                      \
+      SymX(__gmpn_gcd_1)                       \
+      SymX(__gmpz_cmp)                         \
+      SymX(__gmpz_cmp_si)                      \
+      SymX(__gmpz_cmp_ui)                      \
+      SymX(__gmpz_get_si)                      \
+      SymX(__gmpz_get_ui)                      \
+      SymX(__int_encodeDouble)                 \
+      SymX(__int_encodeFloat)                  \
+      SymX(andIntegerzh_fast)                  \
+      SymX(blockAsyncExceptionszh_fast)                \
+      SymX(catchzh_fast)                       \
+      SymX(cmp_thread)                         \
+      SymX(complementIntegerzh_fast)           \
+      SymX(cmpIntegerzh_fast)                  \
+      SymX(cmpIntegerIntzh_fast)               \
+      SymX(createAdjustor)                     \
+      SymX(decodeDoublezh_fast)                        \
+      SymX(decodeFloatzh_fast)                 \
+      SymX(defaultsHook)                       \
+      SymX(delayzh_fast)                       \
+      SymX(deRefWeakzh_fast)                   \
+      SymX(deRefStablePtrzh_fast)              \
+      SymX(divExactIntegerzh_fast)             \
+      SymX(divModIntegerzh_fast)               \
+      SymX(forkzh_fast)                                \
+      SymX(forkProcesszh_fast)                  \
+      SymX(freeHaskellFunctionPtr)             \
+      SymX(freeStablePtr)                      \
+      SymX(gcdIntegerzh_fast)                  \
+      SymX(gcdIntegerIntzh_fast)               \
+      SymX(gcdIntzh_fast)                      \
+      SymX(getProgArgv)                                \
+      SymX(getStablePtr)                       \
+      SymX(int2Integerzh_fast)                 \
+      SymX(integer2Intzh_fast)                 \
+      SymX(integer2Wordzh_fast)                        \
+      SymX(isDoubleDenormalized)               \
+      SymX(isDoubleInfinite)                   \
+      SymX(isDoubleNaN)                                \
+      SymX(isDoubleNegativeZero)               \
+      SymX(isEmptyMVarzh_fast)                 \
+      SymX(isFloatDenormalized)                        \
+      SymX(isFloatInfinite)                    \
+      SymX(isFloatNaN)                         \
+      SymX(isFloatNegativeZero)                        \
+      SymX(killThreadzh_fast)                  \
+      SymX(makeStablePtrzh_fast)               \
+      SymX(minusIntegerzh_fast)                        \
+      SymX(mkApUpd0zh_fast)                    \
+      SymX(myThreadIdzh_fast)                  \
+      SymX(labelThreadzh_fast)                  \
+      SymX(newArrayzh_fast)                    \
+      SymX(newBCOzh_fast)                      \
+      SymX(newByteArrayzh_fast)                        \
+      SymX(newCAF)                             \
+      SymX(newMVarzh_fast)                     \
+      SymX(newMutVarzh_fast)                   \
+      SymX(newPinnedByteArrayzh_fast)          \
+      SymX(orIntegerzh_fast)                   \
+      SymX(performGC)                          \
+      SymX(plusIntegerzh_fast)                 \
+      SymX(prog_argc)                          \
+      SymX(prog_argv)                          \
+      SymX(putMVarzh_fast)                     \
+      SymX(quotIntegerzh_fast)                 \
+      SymX(quotRemIntegerzh_fast)              \
+      SymX(raisezh_fast)                       \
+      SymX(remIntegerzh_fast)                  \
+      SymX(resetNonBlockingFd)                 \
+      SymX(resumeThread)                       \
+      SymX(rts_apply)                          \
+      SymX(rts_checkSchedStatus)               \
+      SymX(rts_eval)                           \
+      SymX(rts_evalIO)                         \
+      SymX(rts_evalLazyIO)                     \
+      SymX(rts_eval_)                          \
+      SymX(rts_getAddr)                                \
+      SymX(rts_getBool)                                \
+      SymX(rts_getChar)                                \
+      SymX(rts_getDouble)                      \
+      SymX(rts_getFloat)                       \
+      SymX(rts_getInt)                         \
+      SymX(rts_getInt32)                       \
+      SymX(rts_getPtr)                         \
+      SymX(rts_getStablePtr)                   \
+      SymX(rts_getThreadId)                    \
+      SymX(rts_getWord)                                \
+      SymX(rts_getWord32)                      \
+      SymX(rts_mkAddr)                         \
+      SymX(rts_mkBool)                         \
+      SymX(rts_mkChar)                         \
+      SymX(rts_mkDouble)                       \
+      SymX(rts_mkFloat)                                \
+      SymX(rts_mkInt)                          \
+      SymX(rts_mkInt16)                                \
+      SymX(rts_mkInt32)                                \
+      SymX(rts_mkInt64)                                \
+      SymX(rts_mkInt8)                         \
+      SymX(rts_mkPtr)                          \
+      SymX(rts_mkStablePtr)                    \
+      SymX(rts_mkString)                       \
+      SymX(rts_mkWord)                         \
+      SymX(rts_mkWord16)                       \
+      SymX(rts_mkWord32)                       \
+      SymX(rts_mkWord64)                       \
+      SymX(rts_mkWord8)                                \
+      SymX(run_queue_hd)                       \
+      SymX(setProgArgv)                                \
+      SymX(shutdownHaskellAndExit)             \
+      SymX(stable_ptr_table)                   \
+      SymX(stackOverflow)                      \
+      SymX(stg_CAF_BLACKHOLE_info)             \
+      SymX(stg_CHARLIKE_closure)               \
+      SymX(stg_EMPTY_MVAR_info)                        \
+      SymX(stg_IND_STATIC_info)                        \
+      SymX(stg_INTLIKE_closure)                        \
+      SymX(stg_MUT_ARR_PTRS_FROZEN_info)       \
+      SymX(stg_WEAK_info)                       \
       SymX(stg_ap_1_upd_info)                  \
       SymX(stg_ap_2_upd_info)                  \
       SymX(stg_ap_3_upd_info)                  \
       SymX(stg_ap_1_upd_info)                  \
       SymX(stg_ap_2_upd_info)                  \
       SymX(stg_ap_3_upd_info)                  \
@@ -146,7 +317,14 @@ typedef struct _RtsSymbolVal {
       SymX(stg_ap_6_upd_info)                  \
       SymX(stg_ap_7_upd_info)                  \
       SymX(stg_ap_8_upd_info)                  \
       SymX(stg_ap_6_upd_info)                  \
       SymX(stg_ap_7_upd_info)                  \
       SymX(stg_ap_8_upd_info)                  \
+      SymX(stg_exit)                           \
       SymX(stg_sel_0_upd_info)                 \
       SymX(stg_sel_0_upd_info)                 \
+      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_sel_1_upd_info)                 \
       SymX(stg_sel_2_upd_info)                 \
       SymX(stg_sel_3_upd_info)                 \
       SymX(stg_sel_1_upd_info)                 \
       SymX(stg_sel_2_upd_info)                 \
       SymX(stg_sel_3_upd_info)                 \
@@ -156,183 +334,26 @@ typedef struct _RtsSymbolVal {
       SymX(stg_sel_7_upd_info)                 \
       SymX(stg_sel_8_upd_info)                 \
       SymX(stg_sel_9_upd_info)                 \
       SymX(stg_sel_7_upd_info)                 \
       SymX(stg_sel_8_upd_info)                 \
       SymX(stg_sel_9_upd_info)                 \
-      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_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(newCAF)                             \
-      SymX(newBCOzh_fast)                      \
-      SymX(mkApUpd0zh_fast)                    \
-      SymX(putMVarzh_fast)                     \
-      SymX(newMVarzh_fast)                     \
+      SymX(stg_upd_frame_info)                 \
+      SymX(__stg_update_PAP)                   \
+      SymX(suspendThread)                      \
       SymX(takeMVarzh_fast)                    \
       SymX(takeMVarzh_fast)                    \
-      SymX(tryTakeMVarzh_fast)                 \
+      SymX(timesIntegerzh_fast)                        \
       SymX(tryPutMVarzh_fast)                  \
       SymX(tryPutMVarzh_fast)                  \
-      SymX(catchzh_fast)                       \
-      SymX(raisezh_fast)                       \
-      SymX(forkzh_fast)                                \
-      SymX(delayzh_fast)                       \
-      SymX(yieldzh_fast)                       \
-      SymX(killThreadzh_fast)                  \
+      SymX(tryTakeMVarzh_fast)                 \
+      SymX(unblockAsyncExceptionszh_fast)      \
+      SymX(unsafeThawArrayzh_fast)             \
       SymX(waitReadzh_fast)                    \
       SymX(waitWritezh_fast)                   \
       SymX(waitReadzh_fast)                    \
       SymX(waitWritezh_fast)                   \
-      SymX(suspendThread)                      \
-      SymX(resumeThread)                       \
-      SymX(stackOverflow)                      \
-      SymX(int2Integerzh_fast)                 \
       SymX(word2Integerzh_fast)                        \
       SymX(word2Integerzh_fast)                        \
-      Maybe_ForeignObj                         \
-      SymX(__encodeDouble)                     \
-      SymX(decodeDoublezh_fast)                        \
-      SymX(decodeFloatzh_fast)                 \
-      SymX(gcdIntegerzh_fast)                  \
-      SymX(newArrayzh_fast)                    \
-      SymX(unsafeThawArrayzh_fast)             \
-      SymX(newByteArrayzh_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(andIntegerzh_fast)                  \
-      SymX(orIntegerzh_fast)                   \
       SymX(xorIntegerzh_fast)                  \
       SymX(xorIntegerzh_fast)                  \
-      SymX(complementIntegerzh_fast)           \
-      Maybe_Stable_Names                       \
-      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(__gmpz_get_si)                      \
-      SymX(__gmpz_get_ui)                      \
-      SymX(prog_argv)                          \
-      SymX(prog_argc)                          \
-      SymX(resetNonBlockingFd)                 \
-      SymX(performGC)                          \
-      SymX(getStablePtr)                       \
-      SymX(stable_ptr_table)                   \
-      SymX(shutdownHaskellAndExit)             \
-      Sym(stg_enterStackTop)                   \
-      Sym(stg_yield_to_interpreter)            \
-      Sym(StgReturn)                           \
-      Sym(init_stack)                          \
-      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(createAdjustor)                     \
-      SymX(rts_mkChar)                         \
-      SymX(rts_mkInt)                          \
-      SymX(rts_mkInt8)                         \
-      SymX(rts_mkInt16)                                \
-      SymX(rts_mkInt32)                                \
-      SymX(rts_mkInt64)                                \
-      SymX(rts_mkWord)                         \
-      SymX(rts_mkWord8)                                \
-      SymX(rts_mkWord16)                       \
-      SymX(rts_mkWord32)                       \
-      SymX(rts_mkWord64)                       \
-      SymX(rts_mkPtr)                          \
-      SymX(rts_mkFloat)                                \
-      SymX(rts_mkDouble)                       \
-      SymX(rts_mkStablePtr)                    \
-      SymX(rts_mkBool)                         \
-      SymX(rts_mkString)                       \
-      SymX(rts_apply)                          \
-      SymX(rts_mkAddr)                         \
-      SymX(rts_getChar)                                \
-      SymX(rts_getInt)                         \
-      SymX(rts_getInt32)                       \
-      SymX(rts_getWord)                                \
-      SymX(rts_getWord32)                      \
-      SymX(rts_getPtr)                         \
-      SymX(rts_getFloat)                       \
-      SymX(rts_getDouble)                      \
-      SymX(rts_getStablePtr)                   \
-      SymX(rts_getBool)                                \
-      SymX(rts_getAddr)                                \
-      SymX(rts_eval)                           \
-      SymX(rts_eval_)                          \
-      SymX(rts_evalIO)                         \
-      SymX(rts_evalLazyIO)                     \
-      SymX(rts_checkSchedStatus)
+      SymX(yieldzh_fast)
 
 #ifndef SUPPORT_LONG_LONGS
 #define RTS_LONG_LONG_SYMS /* nothing */
 #else
 #define RTS_LONG_LONG_SYMS                     \
 
 #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 */
       SymX(int64ToIntegerzh_fast)              \
       SymX(word64ToIntegerzh_fast)
 #endif /* SUPPORT_LONG_LONGS */
@@ -366,6 +387,40 @@ static RtsSymbolVal rtsSyms[] = {
 };
 
 /* -----------------------------------------------------------------------------
 };
 
 /* -----------------------------------------------------------------------------
+ * Insert symbols into hash tables, checking for duplicates.
+ */
+static void ghciInsertStrHashTable ( char* obj_name,
+                                     HashTable *table,
+                                     char* key,
+                                     void *data
+                                  )
+{
+   if (lookupHashTable(table, (StgWord)key) == NULL)
+   {
+      insertStrHashTable(table, (StgWord)key, data);
+      return;
+   }
+   fprintf(stderr,
+      "\n\n"
+      "GHCi runtime linker: fatal error: I found a duplicate definition for symbol\n"
+      "   %s\n"
+      "whilst processing object file\n"
+      "   %s\n"
+      "This could be caused by:\n"
+      "   * Loading two different object files which export the same symbol\n"
+      "   * Specifying the same object file twice on the GHCi command line\n"
+      "   * An incorrect `package.conf' entry, causing some object to be\n"
+      "     loaded twice.\n"
+      "GHCi cannot safely continue in this situation.  Exiting now.  Sorry.\n"
+      "\n",
+      (char*)key,
+      obj_name
+   );
+   exit(1);
+}
+
+
+/* -----------------------------------------------------------------------------
  * initialize the object linker
  */
 #if defined(OBJFORMAT_ELF)
  * initialize the object linker
  */
 #if defined(OBJFORMAT_ELF)
@@ -381,7 +436,8 @@ initLinker( void )
 
     /* populate the symbol table with stuff from the RTS */
     for (sym = rtsSyms; sym->lbl != NULL; sym++) {
 
     /* populate the symbol table with stuff from the RTS */
     for (sym = rtsSyms; sym->lbl != NULL; sym++) {
-       insertStrHashTable(symhash, sym->lbl, sym->addr);
+       ghciInsertStrHashTable("(GHCi built-in symbols)",
+                               symhash, sym->lbl, sym->addr);
     }
 #   if defined(OBJFORMAT_ELF)
     dl_prog_handle = dlopen(NULL, RTLD_LAZY);
     }
 #   if defined(OBJFORMAT_ELF)
     dl_prog_handle = dlopen(NULL, RTLD_LAZY);
@@ -395,7 +451,7 @@ initLinker( void )
  * lookupSymbol() will subsequently see them by dlsym on the program's
  * dl-handle.  Returns NULL if success, otherwise ptr to an err msg.
  *
  * lookupSymbol() will subsequently see them by dlsym on the program's
  * dl-handle.  Returns NULL if success, otherwise ptr to an err msg.
  *
- * In the PEi386 case, open the DLLs and put handles to them in a 
+ * In the PEi386 case, open the DLLs and put handles to them in a
  * linked list.  When looking for a symbol, try all handles in the
  * list.
  */
  * linked list.  When looking for a symbol, try all handles in the
  * list.
  */
@@ -408,7 +464,7 @@ typedef
       char*              name;
       struct _OpenedDLL* next;
       HINSTANCE instance;
       char*              name;
       struct _OpenedDLL* next;
       HINSTANCE instance;
-   } 
+   }
    OpenedDLL;
 
 /* A list thereof. */
    OpenedDLL;
 
 /* A list thereof. */
@@ -418,7 +474,7 @@ static OpenedDLL* opened_dlls = NULL;
 
 
 char*
 
 
 char*
-addDLL ( char* path, char* dll_name )
+addDLL ( __attribute((unused)) char* path, char* dll_name )
 {
 #  if defined(OBJFORMAT_ELF)
    void *hdl;
 {
 #  if defined(OBJFORMAT_ELF)
    void *hdl;
@@ -463,11 +519,17 @@ addDLL ( char* path, char* dll_name )
    buf = stgMallocBytes(strlen(dll_name) + 10, "addDLL");
    sprintf(buf, "%s.DLL", dll_name);
    instance = LoadLibrary(buf);
    buf = stgMallocBytes(strlen(dll_name) + 10, "addDLL");
    sprintf(buf, "%s.DLL", dll_name);
    instance = LoadLibrary(buf);
-   free(buf);
    if (instance == NULL) {
    if (instance == NULL) {
-     /* LoadLibrary failed; return a ptr to the error msg. */
-     return "addDLL: unknown error";
+        sprintf(buf, "%s.DRV", dll_name);              // KAA: allow loading of drivers (like winspool.drv)
+        instance = LoadLibrary(buf);
+        if (instance == NULL) {
+               free(buf);
+
+           /* LoadLibrary failed; return a ptr to the error msg. */
+           return "addDLL: unknown error";
+        }
    }
    }
+   free(buf);
 
    o_dll = stgMallocBytes( sizeof(OpenedDLL), "addDLL" );
    o_dll->name     = stgMallocBytes(1+strlen(dll_name), "addDLL");
 
    o_dll = stgMallocBytes( sizeof(OpenedDLL), "addDLL" );
    o_dll->name     = stgMallocBytes(1+strlen(dll_name), "addDLL");
@@ -484,7 +546,7 @@ addDLL ( char* path, char* dll_name )
 
 /* -----------------------------------------------------------------------------
  * lookup a symbol in the hash table
 
 /* -----------------------------------------------------------------------------
  * lookup a symbol in the hash table
- */  
+ */
 void *
 lookupSymbol( char *lbl )
 {
 void *
 lookupSymbol( char *lbl )
 {
@@ -499,18 +561,37 @@ lookupSymbol( char *lbl )
         OpenedDLL* o_dll;
         void* sym;
         for (o_dll = opened_dlls; o_dll != NULL; o_dll = o_dll->next) {
         OpenedDLL* o_dll;
         void* sym;
         for (o_dll = opened_dlls; o_dll != NULL; o_dll = o_dll->next) {
-           /* fprintf(stderr, "look in %s for %s\n", o_dll->name, lbl); */
+         /* fprintf(stderr, "look in %s for %s\n", o_dll->name, lbl); */
+           if (lbl[0] == '_') {
+              /* HACK: if the name has an initial underscore, try stripping
+                 it off & look that up first. I've yet to verify whether there's
+                 a Rule that governs whether an initial '_' *should always* be
+                 stripped off when mapping from import lib name to the DLL name.
+              */
+              sym = GetProcAddress(o_dll->instance, (lbl+1));
+              if (sym != NULL) {
+               /*fprintf(stderr, "found %s in %s\n", lbl+1,o_dll->name); fflush(stderr);*/
+               return sym;
+             }
+           }
            sym = GetProcAddress(o_dll->instance, lbl);
            sym = GetProcAddress(o_dll->instance, lbl);
-           if (sym != NULL) return sym;
+           if (sym != NULL) {
+            /*fprintf(stderr, "found %s in %s\n", lbl,o_dll->name); fflush(stderr);*/
+            return sym;
+          }
         }
         return NULL;
         }
         return NULL;
+#       else
+        ASSERT(2+2 == 5);
+        return NULL;
 #       endif
     } else {
        return val;
     }
 }
 
 #       endif
     } else {
        return val;
     }
 }
 
-static 
+static
+__attribute((unused))
 void *
 lookupLocalSymbol( ObjectCode* oc, char *lbl )
 {
 void *
 lookupLocalSymbol( ObjectCode* oc, char *lbl )
 {
@@ -526,6 +607,42 @@ lookupLocalSymbol( ObjectCode* oc, char *lbl )
 
 
 /* -----------------------------------------------------------------------------
 
 
 /* -----------------------------------------------------------------------------
+ * Debugging aid: look in GHCi's object symbol tables for symbols
+ * within DELTA bytes of the specified address, and show their names.
+ */
+#ifdef DEBUG
+void ghci_enquire ( char* addr );
+
+void ghci_enquire ( char* addr )
+{
+   int   i;
+   char* sym;
+   char* a;
+   const int DELTA = 64;
+   ObjectCode* oc;
+   for (oc = objects; oc; oc = oc->next) {
+      for (i = 0; i < oc->n_symbols; i++) {
+         sym = oc->symbols[i];
+         if (sym == NULL) continue;
+         /* fprintf(stderr, "enquire %p %p\n", sym, oc->lochash); */
+         a = NULL;
+         if (oc->lochash != NULL)
+            a = lookupStrHashTable(oc->lochash, sym);
+         if (a == NULL)
+            a = lookupStrHashTable(symhash, sym);
+         if (a == NULL) {
+            /* fprintf(stderr, "ghci_enquire: can't find %s\n", sym); */
+         }
+         else if (addr-DELTA <= a && a <= addr+DELTA) {
+            fprintf(stderr, "%p + %3d  ==  `%s'\n", addr, a - addr, sym);
+         }
+      }
+   }
+}
+#endif
+
+
+/* -----------------------------------------------------------------------------
  * Load an obj (populate the global symbol table, but don't resolve yet)
  *
  * Returns: 1 if ok, 0 on error.
  * Load an obj (populate the global symbol table, but don't resolve yet)
  *
  * Returns: 1 if ok, 0 on error.
@@ -539,14 +656,27 @@ loadObj( char *path )
    FILE *f;
 
    /* fprintf(stderr, "loadObj %s\n", path ); */
    FILE *f;
 
    /* fprintf(stderr, "loadObj %s\n", path ); */
-#  ifdef DEBUG
-   /* assert that we haven't already loaded this object */
-   { 
+
+   /* Check that we haven't already loaded this object.  Don't give up
+      at this stage; ocGetNames_* will barf later. */
+   {
        ObjectCode *o;
        ObjectCode *o;
-       for (o = objects; o; o = o->next)
-          ASSERT(strcmp(o->fileName, path));
+       int is_dup = 0;
+       for (o = objects; o; o = o->next) {
+          if (0 == strcmp(o->fileName, path))
+             is_dup = 1;
+       }
+       if (is_dup) {
+        fprintf(stderr,
+            "\n\n"
+            "GHCi runtime linker: warning: looks like you're trying to load the\n"
+            "same object file twice:\n"
+            "   %s\n"
+            "GHCi will continue, but a duplicate-symbol error may shortly follow.\n"
+            "\n"
+            , path);
+       }
    }
    }
-#  endif /* DEBUG */   
 
    oc = stgMallocBytes(sizeof(ObjectCode), "loadObj(oc)");
 
 
    oc = stgMallocBytes(sizeof(ObjectCode), "loadObj(oc)");
 
@@ -571,6 +701,7 @@ loadObj( char *path )
    oc->symbols           = NULL;
    oc->sections          = NULL;
    oc->lochash           = allocStrHashTable();
    oc->symbols           = NULL;
    oc->sections          = NULL;
    oc->lochash           = allocStrHashTable();
+   oc->proddables        = NULL;
 
    /* chain it onto the list of objects */
    oc->next              = objects;
 
    /* chain it onto the list of objects */
    oc->next              = objects;
@@ -618,7 +749,7 @@ loadObj( char *path )
  *
  * Returns: 1 if ok, 0 on error.
  */
  *
  * Returns: 1 if ok, 0 on error.
  */
-HsInt 
+HsInt
 resolveObjs( void )
 {
     ObjectCode *oc;
 resolveObjs( void )
 {
     ObjectCode *oc;
@@ -658,7 +789,7 @@ unloadObj( char *path )
            /* Remove all the mappings for the symbols within this
             * object..
             */
            /* Remove all the mappings for the symbols within this
             * object..
             */
-           { 
+           {
                 int i;
                 for (i = 0; i < oc->n_symbols; i++) {
                    if (oc->symbols[i] != NULL) {
                 int i;
                 for (i = 0; i < oc->n_symbols; i++) {
                    if (oc->symbols[i] != NULL) {
@@ -691,17 +822,96 @@ unloadObj( char *path )
     return 0;
 }
 
     return 0;
 }
 
+/* -----------------------------------------------------------------------------
+ * Sanity checking.  For each ObjectCode, maintain a list of address ranges
+ * which may be prodded during relocation, and abort if we try and write
+ * outside any of these.
+ */
+static void addProddableBlock ( ObjectCode* oc, void* start, int size )
+{
+   ProddableBlock* pb
+      = stgMallocBytes(sizeof(ProddableBlock), "addProddableBlock");
+   /* fprintf(stderr, "aPB %p %p %d\n", oc, start, size); */
+   ASSERT(size > 0);
+   pb->start      = start;
+   pb->size       = size;
+   pb->next       = oc->proddables;
+   oc->proddables = pb;
+}
+
+static void checkProddableBlock ( ObjectCode* oc, void* addr )
+{
+   ProddableBlock* pb;
+   for (pb = oc->proddables; pb != NULL; pb = pb->next) {
+      char* s = (char*)(pb->start);
+      char* e = s + pb->size - 1;
+      char* a = (char*)addr;
+      /* Assumes that the biggest fixup involves a 4-byte write.  This
+         probably needs to be changed to 8 (ie, +7) on 64-bit
+         plats. */
+      if (a >= s && (a+3) <= e) return;
+   }
+   barf("checkProddableBlock: invalid fixup in runtime linker");
+}
+
+/* -----------------------------------------------------------------------------
+ * Section management.
+ */
+static void addSection ( ObjectCode* oc, SectionKind kind,
+                         void* start, void* end )
+{
+   Section* s   = stgMallocBytes(sizeof(Section), "addSection");
+   s->start     = start;
+   s->end       = end;
+   s->kind      = kind;
+   s->next      = oc->sections;
+   oc->sections = s;
+   /*
+   fprintf(stderr, "addSection: %p-%p (size %d), kind %d\n",
+                   start, ((char*)end)-1, end - start + 1, kind );
+   */
+}
+
+
+
 /* --------------------------------------------------------------------------
  * PEi386 specifics (Win32 targets)
  * ------------------------------------------------------------------------*/
 
 /* --------------------------------------------------------------------------
  * PEi386 specifics (Win32 targets)
  * ------------------------------------------------------------------------*/
 
-/* The information for this linker comes from 
-      Microsoft Portable Executable 
+/* 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.
       and Common Object File Format Specification
       revision 5.1 January 1998
    which SimonM says comes from the MS Developer Network CDs.
+
+   It can be found there (on older CDs), but can also be found
+   online at:
+
+      http://www.microsoft.com/hwdev/hardware/PECOFF.asp
+
+   (this is Rev 6.0 from February 1999).
+
+   Things move, so if that fails, try searching for it via
+
+      http://www.google.com/search?q=PE+COFF+specification
+
+   The ultimate reference for the PE format is the Winnt.h
+   header file that comes with the Platform SDKs; as always,
+   implementations will drift wrt their documentation.
+
+   A good background article on the PE format is Matt Pietrek's
+   March 1994 article in Microsoft System Journal (MSJ)
+   (Vol.9, No. 3): "Peering Inside the PE: A Tour of the
+   Win32 Portable Executable File Format." The info in there
+   has recently been updated in a two part article in
+   MSDN magazine, issues Feb and March 2002,
+   "Inside Windows: An In-Depth Look into the Win32 Portable
+   Executable File Format"
+
+   John Levine's book "Linkers and Loaders" contains useful
+   info on PE too.
 */
 */
-      
+
 
 #if defined(OBJFORMAT_PEi386)
 
 
 #if defined(OBJFORMAT_PEi386)
 
@@ -713,7 +923,7 @@ typedef unsigned int   UInt32;
 typedef          int   Int32;
 
 
 typedef          int   Int32;
 
 
-typedef 
+typedef
    struct {
       UInt16 Machine;
       UInt16 NumberOfSections;
    struct {
       UInt16 Machine;
       UInt16 NumberOfSections;
@@ -728,7 +938,7 @@ typedef
 #define sizeof_COFF_header 20
 
 
 #define sizeof_COFF_header 20
 
 
-typedef 
+typedef
    struct {
       UChar  Name[8];
       UInt32 VirtualSize;
    struct {
       UChar  Name[8];
       UInt32 VirtualSize;
@@ -739,7 +949,7 @@ typedef
       UInt32 PointerToLinenumbers;
       UInt16 NumberOfRelocations;
       UInt16 NumberOfLineNumbers;
       UInt32 PointerToLinenumbers;
       UInt16 NumberOfRelocations;
       UInt16 NumberOfLineNumbers;
-      UInt32 Characteristics; 
+      UInt32 Characteristics;
    }
    COFF_section;
 
    }
    COFF_section;
 
@@ -791,6 +1001,7 @@ typedef
 /* From PE spec doc, section 4.1 */
 #define MYIMAGE_SCN_CNT_CODE             0x00000020
 #define MYIMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
 /* From PE spec doc, section 4.1 */
 #define MYIMAGE_SCN_CNT_CODE             0x00000020
 #define MYIMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
+#define MYIMAGE_SCN_LNK_NRELOC_OVFL      0x01000000
 
 /* From PE spec doc, section 5.2.1 */
 #define MYIMAGE_REL_I386_DIR32           0x0006
 
 /* From PE spec doc, section 5.2.1 */
 #define MYIMAGE_REL_I386_DIR32           0x0006
@@ -799,7 +1010,7 @@ typedef
 
 /* We use myindex to calculate array addresses, rather than
    simply doing the normal subscript thing.  That's because
 
 /* 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 
+   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
    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
@@ -854,7 +1065,7 @@ cstring_from_COFF_symbol_name ( UChar* name, UChar* strtab )
 {
    UChar* newstr;
    /* If the string is longer than 8 bytes, look in the
 {
    UChar* newstr;
    /* If the string is longer than 8 bytes, look in the
-      string table for it -- this will be correctly zero terminated. 
+      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);
    */
    if (name[0]==0 && name[1]==0 && name[2]==0 && name[3]==0) {
       UInt32 strtab_offset = * (UInt32*)(name+4);
@@ -880,23 +1091,23 @@ static COFF_section *
 findPEi386SectionCalled ( ObjectCode* oc,  char* name )
 {
    int i;
 findPEi386SectionCalled ( ObjectCode* oc,  char* name )
 {
    int i;
-   COFF_header* hdr 
+   COFF_header* hdr
       = (COFF_header*)(oc->image);
       = (COFF_header*)(oc->image);
-   COFF_section* sectab 
+   COFF_section* sectab
       = (COFF_section*) (
       = (COFF_section*) (
-           ((UChar*)(oc->image)) 
+           ((UChar*)(oc->image))
            + sizeof_COFF_header + hdr->SizeOfOptionalHeader
         );
    for (i = 0; i < hdr->NumberOfSections; i++) {
       UChar* n1;
       UChar* n2;
            + sizeof_COFF_header + hdr->SizeOfOptionalHeader
         );
    for (i = 0; i < hdr->NumberOfSections; i++) {
       UChar* n1;
       UChar* n2;
-      COFF_section* section_i 
+      COFF_section* section_i
          = (COFF_section*)
            myindex ( sizeof_COFF_section, sectab, i );
       n1 = (UChar*) &(section_i->Name);
       n2 = name;
          = (COFF_section*)
            myindex ( sizeof_COFF_section, sectab, i );
       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] && 
+      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;
    }
           n1[6]==n2[6] && n1[7]==n2[7])
          return section_i;
    }
@@ -911,7 +1122,7 @@ zapTrailingAtSign ( UChar* sym )
 #  define my_isdigit(c) ((c) >= '0' && (c) <= '9')
    int i, j;
    if (sym[0] == 0) return;
 #  define my_isdigit(c) ((c) >= '0' && (c) <= '9')
    int i, j;
    if (sym[0] == 0) return;
-   i = 0; 
+   i = 0;
    while (sym[i] != 0) i++;
    i--;
    j = i;
    while (sym[i] != 0) i++;
    i--;
    j = i;
@@ -924,7 +1135,8 @@ zapTrailingAtSign ( UChar* sym )
 static int
 ocVerifyImage_PEi386 ( ObjectCode* oc )
 {
 static int
 ocVerifyImage_PEi386 ( ObjectCode* oc )
 {
-   int i, j;
+   int i;
+   UInt32 j, noRelocs;
    COFF_header*  hdr;
    COFF_section* sectab;
    COFF_symbol*  symtab;
    COFF_header*  hdr;
    COFF_section* sectab;
    COFF_symbol*  symtab;
@@ -932,12 +1144,12 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
    /* fprintf(stderr, "\nLOADING %s\n", oc->fileName); */
    hdr = (COFF_header*)(oc->image);
    sectab = (COFF_section*) (
    /* fprintf(stderr, "\nLOADING %s\n", oc->fileName); */
    hdr = (COFF_header*)(oc->image);
    sectab = (COFF_section*) (
-               ((UChar*)(oc->image)) 
+               ((UChar*)(oc->image))
                + sizeof_COFF_header + hdr->SizeOfOptionalHeader
             );
    symtab = (COFF_symbol*) (
                ((UChar*)(oc->image))
                + sizeof_COFF_header + hdr->SizeOfOptionalHeader
             );
    symtab = (COFF_symbol*) (
                ((UChar*)(oc->image))
-               + hdr->PointerToSymbolTable 
+               + hdr->PointerToSymbolTable
             );
    strtab = ((UChar*)symtab)
             + hdr->NumberOfSymbols * sizeof_COFF_symbol;
             );
    strtab = ((UChar*)symtab)
             + hdr->NumberOfSymbols * sizeof_COFF_symbol;
@@ -959,40 +1171,48 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
    }
    if ( (hdr->Characteristics & MYIMAGE_FILE_BYTES_REVERSED_HI)
         /* || !(hdr->Characteristics & MYIMAGE_FILE_32BIT_MACHINE) */ ) {
    }
    if ( (hdr->Characteristics & MYIMAGE_FILE_BYTES_REVERSED_HI)
         /* || !(hdr->Characteristics & MYIMAGE_FILE_32BIT_MACHINE) */ ) {
-      belch("Invalid PEi386 word size or endiannness: %d", 
+      belch("Invalid PEi386 word size or endiannness: %d",
             (int)(hdr->Characteristics));
       return 0;
    }
             (int)(hdr->Characteristics));
       return 0;
    }
+   /* If the string table size is way crazy, this might indicate that
+      there are more than 64k relocations, despite claims to the
+      contrary.  Hence this test. */
    /* fprintf(stderr, "strtab size %d\n", * (UInt32*)strtab); */
    /* fprintf(stderr, "strtab size %d\n", * (UInt32*)strtab); */
-   if (* (UInt32*)strtab > 510000) {
+#if 0
+   if ( (*(UInt32*)strtab) > 600000 ) {
+      /* Note that 600k has no special significance other than being
+         big enough to handle the almost-2MB-sized lumps that
+         constitute HSwin32*.o. */
       belch("PEi386 object has suspiciously large string table; > 64k relocs?");
       return 0;
    }
       belch("PEi386 object has suspiciously large string table; > 64k relocs?");
       return 0;
    }
+#endif
 
    /* No further verification after this point; only debug printing. */
    i = 0;
    IF_DEBUG(linker, i=1);
    if (i == 0) return 1;
 
 
    /* No further verification after this point; only debug printing. */
    i = 0;
    IF_DEBUG(linker, i=1);
    if (i == 0) return 1;
 
-   fprintf ( stderr, 
+   fprintf ( stderr,
              "sectab offset = %d\n", ((UChar*)sectab) - ((UChar*)hdr) );
              "sectab offset = %d\n", ((UChar*)sectab) - ((UChar*)hdr) );
-   fprintf ( stderr, 
+   fprintf ( stderr,
              "symtab offset = %d\n", ((UChar*)symtab) - ((UChar*)hdr) );
              "symtab offset = %d\n", ((UChar*)symtab) - ((UChar*)hdr) );
-   fprintf ( stderr, 
+   fprintf ( stderr,
              "strtab offset = %d\n", ((UChar*)strtab) - ((UChar*)hdr) );
 
    fprintf ( stderr, "\n" );
              "strtab offset = %d\n", ((UChar*)strtab) - ((UChar*)hdr) );
 
    fprintf ( stderr, "\n" );
-   fprintf ( stderr, 
+   fprintf ( stderr,
              "Machine:           0x%x\n", (UInt32)(hdr->Machine) );
              "Machine:           0x%x\n", (UInt32)(hdr->Machine) );
-   fprintf ( stderr, 
+   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) );
              "# 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, 
+   fprintf ( stderr,
              "# symbols:         %d\n",   (UInt32)(hdr->NumberOfSymbols) );
              "# symbols:         %d\n",   (UInt32)(hdr->NumberOfSymbols) );
-   fprintf ( stderr, 
+   fprintf ( stderr,
              "sz of opt hdr:     %d\n",   (UInt32)(hdr->SizeOfOptionalHeader) );
    fprintf ( stderr,
              "characteristics:   0x%x\n", (UInt32)(hdr->Characteristics) );
              "sz of opt hdr:     %d\n",   (UInt32)(hdr->SizeOfOptionalHeader) );
    fprintf ( stderr,
              "characteristics:   0x%x\n", (UInt32)(hdr->Characteristics) );
@@ -1004,54 +1224,72 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
       COFF_section* sectab_i
          = (COFF_section*)
            myindex ( sizeof_COFF_section, sectab, i );
       COFF_section* sectab_i
          = (COFF_section*)
            myindex ( sizeof_COFF_section, sectab, i );
-      fprintf ( stderr, 
+      fprintf ( stderr,
                 "\n"
                 "section %d\n"
                 "     name `",
                 "\n"
                 "section %d\n"
                 "     name `",
-                i 
+                i
               );
       printName ( sectab_i->Name, strtab );
               );
       printName ( sectab_i->Name, strtab );
-      fprintf ( stderr, 
+      fprintf ( stderr,
                 "'\n"
                 "    vsize %d\n"
                 "    vaddr %d\n"
                 "  data sz %d\n"
                 " data off %d\n"
                 "  num rel %d\n"
                 "'\n"
                 "    vsize %d\n"
                 "    vaddr %d\n"
                 "  data sz %d\n"
                 " data off %d\n"
                 "  num rel %d\n"
-                "  off rel %d\n",
+                "  off rel %d\n"
+                "  ptr raw 0x%x\n",
                 sectab_i->VirtualSize,
                 sectab_i->VirtualAddress,
                 sectab_i->SizeOfRawData,
                 sectab_i->PointerToRawData,
                 sectab_i->NumberOfRelocations,
                 sectab_i->VirtualSize,
                 sectab_i->VirtualAddress,
                 sectab_i->SizeOfRawData,
                 sectab_i->PointerToRawData,
                 sectab_i->NumberOfRelocations,
-                sectab_i->PointerToRelocations
+                sectab_i->PointerToRelocations,
+                sectab_i->PointerToRawData
               );
       reltab = (COFF_reloc*) (
                   ((UChar*)(oc->image)) + sectab_i->PointerToRelocations
                );
 
               );
       reltab = (COFF_reloc*) (
                   ((UChar*)(oc->image)) + sectab_i->PointerToRelocations
                );
 
-      for (j = 0; j < sectab_i->NumberOfRelocations; j++) {
+      if ( sectab_i->Characteristics & MYIMAGE_SCN_LNK_NRELOC_OVFL ) {
+       /* If the relocation field (a short) has overflowed, the
+        * real count can be found in the first reloc entry.
+        *
+        * See Section 4.1 (last para) of the PE spec (rev6.0).
+        */
+        COFF_reloc* rel = (COFF_reloc*)
+                           myindex ( sizeof_COFF_reloc, reltab, 0 );
+       noRelocs = rel->VirtualAddress;
+       j = 1;
+      } else {
+       noRelocs = sectab_i->NumberOfRelocations;
+        j = 0;
+      }
+
+      for (; j < noRelocs; j++) {
          COFF_symbol* sym;
          COFF_reloc* rel = (COFF_reloc*)
                            myindex ( sizeof_COFF_reloc, reltab, j );
          COFF_symbol* sym;
          COFF_reloc* rel = (COFF_reloc*)
                            myindex ( sizeof_COFF_reloc, reltab, j );
-         fprintf ( stderr, 
+         fprintf ( stderr,
                    "        type 0x%-4x   vaddr 0x%-8x   name `",
                    "        type 0x%-4x   vaddr 0x%-8x   name `",
-                   (UInt32)rel->Type, 
+                   (UInt32)rel->Type,
                    rel->VirtualAddress );
          sym = (COFF_symbol*)
                myindex ( sizeof_COFF_symbol, symtab, rel->SymbolTableIndex );
                    rel->VirtualAddress );
          sym = (COFF_symbol*)
                myindex ( sizeof_COFF_symbol, symtab, rel->SymbolTableIndex );
+        /* Hmm..mysterious looking offset - what's it for? SOF */
          printName ( sym->Name, strtab -10 );
          fprintf ( stderr, "'\n" );
       }
          printName ( sym->Name, strtab -10 );
          fprintf ( stderr, "'\n" );
       }
+
       fprintf ( stderr, "\n" );
    }
       fprintf ( stderr, "\n" );
    }
-
    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 < *(Int32*)strtab; i++) {
    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 < *(Int32*)strtab; i++) {
-      if (strtab[i] == 0) 
-         fprintf ( stderr, "\n"); else 
+      if (strtab[i] == 0)
+         fprintf ( stderr, "\n"); else
          fprintf( stderr, "%c", strtab[i] );
    }
    fprintf ( stderr, "--- END  of string table---\n");
          fprintf( stderr, "%c", strtab[i] );
    }
    fprintf ( stderr, "--- END  of string table---\n");
@@ -1063,24 +1301,24 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
       if (i >= (Int32)(hdr->NumberOfSymbols)) break;
       symtab_i = (COFF_symbol*)
                  myindex ( sizeof_COFF_symbol, symtab, i );
       if (i >= (Int32)(hdr->NumberOfSymbols)) break;
       symtab_i = (COFF_symbol*)
                  myindex ( sizeof_COFF_symbol, symtab, i );
-      fprintf ( stderr, 
+      fprintf ( stderr,
                 "symbol %d\n"
                 "     name `",
                 "symbol %d\n"
                 "     name `",
-                i 
+                i
               );
       printName ( symtab_i->Name, strtab );
               );
       printName ( symtab_i->Name, strtab );
-      fprintf ( stderr, 
+      fprintf ( stderr,
                 "'\n"
                 "    value 0x%x\n"
                 "'\n"
                 "    value 0x%x\n"
-                "     sec# %d\n"
+                "   1+sec# %d\n"
                 "     type 0x%x\n"
                 "   sclass 0x%x\n"
                 "     nAux %d\n",
                 symtab_i->Value,
                 "     type 0x%x\n"
                 "   sclass 0x%x\n"
                 "     nAux %d\n",
                 symtab_i->Value,
-                (Int32)(symtab_i->SectionNumber) - 1,
+                (Int32)(symtab_i->SectionNumber),
                 (UInt32)symtab_i->Type,
                 (UInt32)symtab_i->StorageClass,
                 (UInt32)symtab_i->Type,
                 (UInt32)symtab_i->StorageClass,
-                (UInt32)symtab_i->NumberOfAuxSymbols 
+                (UInt32)symtab_i->NumberOfAuxSymbols
               );
       i += symtab_i->NumberOfAuxSymbols;
       i++;
               );
       i += symtab_i->NumberOfAuxSymbols;
       i++;
@@ -1102,116 +1340,177 @@ ocGetNames_PEi386 ( ObjectCode* oc )
    UChar* sname;
    void*  addr;
    int    i;
    UChar* sname;
    void*  addr;
    int    i;
-   
+
    hdr = (COFF_header*)(oc->image);
    sectab = (COFF_section*) (
    hdr = (COFF_header*)(oc->image);
    sectab = (COFF_section*) (
-               ((UChar*)(oc->image)) 
+               ((UChar*)(oc->image))
                + sizeof_COFF_header + hdr->SizeOfOptionalHeader
             );
    symtab = (COFF_symbol*) (
                ((UChar*)(oc->image))
                + sizeof_COFF_header + hdr->SizeOfOptionalHeader
             );
    symtab = (COFF_symbol*) (
                ((UChar*)(oc->image))
-               + hdr->PointerToSymbolTable 
+               + hdr->PointerToSymbolTable
             );
    strtab = ((UChar*)(oc->image))
             + hdr->PointerToSymbolTable
             + hdr->NumberOfSymbols * sizeof_COFF_symbol;
 
             );
    strtab = ((UChar*)(oc->image))
             + hdr->PointerToSymbolTable
             + hdr->NumberOfSymbols * sizeof_COFF_symbol;
 
-   /* Copy exported symbols into the ObjectCode. */
-
-   oc->n_symbols = hdr->NumberOfSymbols;
-   oc->symbols   = stgMallocBytes(oc->n_symbols * sizeof(char*),
-                                  "ocGetNames_PEi386(oc->symbols)");
-   /* Call me paranoid; I don't care. */
-   for (i = 0; i < oc->n_symbols; i++) 
-      oc->symbols[i] = NULL;
-
-   i = 0;
-   while (1) {
-      COFF_symbol* symtab_i;
-      if (i >= (Int32)(hdr->NumberOfSymbols)) break;
-      symtab_i = (COFF_symbol*)
-                 myindex ( sizeof_COFF_symbol, symtab, i );
-
-      if (symtab_i->StorageClass == MYIMAGE_SYM_CLASS_EXTERNAL &&
-          symtab_i->SectionNumber != MYIMAGE_SYM_UNDEFINED) {
-
-         /* This symbol is global and defined, viz, exported */
-         COFF_section* sectabent;
-
-         /* cstring_from_COFF_symbol_name always succeeds. */
-         sname = cstring_from_COFF_symbol_name ( symtab_i->Name, strtab );
+   /* Allocate space for any (local, anonymous) .bss sections. */
 
 
-         /* for MYIMAGE_SYMCLASS_EXTERNAL 
-                && !MYIMAGE_SYM_UNDEFINED,
-            the address of the symbol is: 
-                address of relevant section + offset in section
-         */
-         sectabent = (COFF_section*)
-                     myindex ( sizeof_COFF_section, 
-                               sectab,
-                               symtab_i->SectionNumber-1 );
-         addr = ((UChar*)(oc->image))
-                + (sectabent->PointerToRawData
-                   + symtab_i->Value);
-         /* fprintf(stderr,"addSymbol %p `%s'\n", addr,sname); */
-         IF_DEBUG(linker, belch("addSymbol %p `%s'\n", addr,sname);)
-         ASSERT(i >= 0 && i < oc->n_symbols);
-         oc->symbols[i] = sname;
-         insertStrHashTable(symhash, sname, addr);
-      }
-      i += symtab_i->NumberOfAuxSymbols;
-      i++;
+   for (i = 0; i < hdr->NumberOfSections; i++) {
+      UChar* zspace;
+      COFF_section* sectab_i
+         = (COFF_section*)
+           myindex ( sizeof_COFF_section, sectab, i );
+      if (0 != strcmp(sectab_i->Name, ".bss")) continue;
+      if (sectab_i->VirtualSize == 0) continue;
+      /* This is a non-empty .bss section.  Allocate zeroed space for
+         it, and set its PointerToRawData field such that oc->image +
+         PointerToRawData == addr_of_zeroed_space.  */
+      zspace = stgCallocBytes(1, sectab_i->VirtualSize,
+                              "ocGetNames_PEi386(anonymous bss)");
+      sectab_i->PointerToRawData = ((UChar*)zspace) - ((UChar*)(oc->image));
+      addProddableBlock(oc, zspace, sectab_i->VirtualSize);
+      /* fprintf(stderr, "BSS anon section at 0x%x\n", zspace); */
    }
 
    /* Copy section information into the ObjectCode. */
 
    }
 
    /* Copy section information into the ObjectCode. */
 
-   oc->n_sections = hdr->NumberOfSections;
-   oc->sections = stgMallocBytes( oc->n_sections * sizeof(Section), 
-                                  "ocGetNamesPEi386" );
-
-   for (i = 0; i < oc->n_sections; i++) {
+   for (i = 0; i < hdr->NumberOfSections; i++) {
       UChar* start;
       UChar* end;
       UChar* start;
       UChar* end;
+      UInt32 sz;
 
 
-      SectionKind kind 
+      SectionKind kind
          = SECTIONKIND_OTHER;
       COFF_section* sectab_i
          = (COFF_section*)
            myindex ( sizeof_COFF_section, sectab, i );
       IF_DEBUG(linker, belch("section name = %s\n", sectab_i->Name ));
 
          = SECTIONKIND_OTHER;
       COFF_section* sectab_i
          = (COFF_section*)
            myindex ( sizeof_COFF_section, sectab, i );
       IF_DEBUG(linker, belch("section name = %s\n", sectab_i->Name ));
 
-#if 0
-      /* I'm sure this is the Right Way to do it.  However, the 
+#     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.
       */
          alternative of testing the sectab_i->Name field seems to
          work ok with Cygwin.
       */
-      if (sectab_i->Characteristics & MYIMAGE_SCN_CNT_CODE || 
+      if (sectab_i->Characteristics & MYIMAGE_SCN_CNT_CODE ||
           sectab_i->Characteristics & MYIMAGE_SCN_CNT_INITIALIZED_DATA)
          kind = SECTIONKIND_CODE_OR_RODATA;
           sectab_i->Characteristics & MYIMAGE_SCN_CNT_INITIALIZED_DATA)
          kind = SECTIONKIND_CODE_OR_RODATA;
-#endif
+#     endif
 
 
-      if (0==strcmp(".text",sectab_i->Name))
+      if (0==strcmp(".text",sectab_i->Name) ||
+          0==strcmp(".rodata",sectab_i->Name))
          kind = SECTIONKIND_CODE_OR_RODATA;
       if (0==strcmp(".data",sectab_i->Name) ||
           0==strcmp(".bss",sectab_i->Name))
          kind = SECTIONKIND_RWDATA;
 
          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;
+      ASSERT(sectab_i->SizeOfRawData == 0 || sectab_i->VirtualSize == 0);
+      sz = sectab_i->SizeOfRawData;
+      if (sz < sectab_i->VirtualSize) sz = sectab_i->VirtualSize;
 
 
-      if (kind == SECTIONKIND_OTHER) {
+      start = ((UChar*)(oc->image)) + sectab_i->PointerToRawData;
+      end   = start + sz - 1;
+
+      if (kind == SECTIONKIND_OTHER
+          /* Ignore sections called which contain stabs debugging
+             information. */
+          && 0 != strcmp(".stab", sectab_i->Name)
+          && 0 != strcmp(".stabstr", sectab_i->Name)
+         ) {
          belch("Unknown PEi386 section name `%s'", sectab_i->Name);
          return 0;
       }
 
          belch("Unknown PEi386 section name `%s'", sectab_i->Name);
          return 0;
       }
 
-      oc->sections[i].start = start;
-      oc->sections[i].end   = end;
-      oc->sections[i].kind  = kind;
+      if (kind != SECTIONKIND_OTHER && end >= start) {
+         addSection(oc, kind, start, end);
+         addProddableBlock(oc, start, end - start + 1);
+      }
+   }
+
+   /* Copy exported symbols into the ObjectCode. */
+
+   oc->n_symbols = hdr->NumberOfSymbols;
+   oc->symbols   = stgMallocBytes(oc->n_symbols * sizeof(char*),
+                                  "ocGetNames_PEi386(oc->symbols)");
+   /* Call me paranoid; I don't care. */
+   for (i = 0; i < oc->n_symbols; i++)
+      oc->symbols[i] = NULL;
+
+   i = 0;
+   while (1) {
+      COFF_symbol* symtab_i;
+      if (i >= (Int32)(hdr->NumberOfSymbols)) break;
+      symtab_i = (COFF_symbol*)
+                 myindex ( sizeof_COFF_symbol, symtab, i );
+
+      addr  = NULL;
+
+      if (symtab_i->StorageClass == MYIMAGE_SYM_CLASS_EXTERNAL
+          && symtab_i->SectionNumber != MYIMAGE_SYM_UNDEFINED) {
+         /* This symbol is global and defined, viz, exported */
+         /* for MYIMAGE_SYMCLASS_EXTERNAL
+                && !MYIMAGE_SYM_UNDEFINED,
+            the address of the symbol is:
+                address of relevant section + offset in section
+         */
+         COFF_section* sectabent
+            = (COFF_section*) myindex ( sizeof_COFF_section,
+                                        sectab,
+                                        symtab_i->SectionNumber-1 );
+         addr = ((UChar*)(oc->image))
+                + (sectabent->PointerToRawData
+                   + symtab_i->Value);
+      }
+      else
+      if (symtab_i->SectionNumber == MYIMAGE_SYM_UNDEFINED
+         && symtab_i->Value > 0) {
+         /* This symbol isn't in any section at all, ie, global bss.
+            Allocate zeroed space for it. */
+         addr = stgCallocBytes(1, symtab_i->Value,
+                               "ocGetNames_PEi386(non-anonymous bss)");
+         addSection(oc, SECTIONKIND_RWDATA, addr,
+                        ((UChar*)addr) + symtab_i->Value - 1);
+         addProddableBlock(oc, addr, symtab_i->Value);
+         /* fprintf(stderr, "BSS      section at 0x%x\n", addr); */
+      }
+
+      if (addr != NULL ) {
+         sname = cstring_from_COFF_symbol_name ( symtab_i->Name, strtab );
+         /* fprintf(stderr,"addSymbol %p `%s \n", addr,sname);  */
+         IF_DEBUG(linker, belch("addSymbol %p `%s'\n", addr,sname);)
+         ASSERT(i >= 0 && i < oc->n_symbols);
+         /* cstring_from_COFF_symbol_name always succeeds. */
+         oc->symbols[i] = sname;
+         ghciInsertStrHashTable(oc->fileName, symhash, sname, addr);
+      } else {
+#        if 0
+         fprintf ( stderr,
+                   "IGNORING symbol %d\n"
+                   "     name `",
+                   i
+                 );
+         printName ( symtab_i->Name, strtab );
+         fprintf ( stderr,
+                   "'\n"
+                   "    value 0x%x\n"
+                   "   1+sec# %d\n"
+                   "     type 0x%x\n"
+                   "   sclass 0x%x\n"
+                   "     nAux %d\n",
+                   symtab_i->Value,
+                   (Int32)(symtab_i->SectionNumber),
+                   (UInt32)symtab_i->Type,
+                   (UInt32)symtab_i->StorageClass,
+                   (UInt32)symtab_i->NumberOfAuxSymbols
+                 );
+#        endif
+      }
+
+      i += symtab_i->NumberOfAuxSymbols;
+      i++;
    }
 
    }
 
-   return 1;   
+   return 1;
 }
 
 
 }
 
 
@@ -1227,7 +1526,8 @@ ocResolve_PEi386 ( ObjectCode* oc )
    UInt32        S;
    UInt32*       pP;
 
    UInt32        S;
    UInt32*       pP;
 
-   int i, j;
+   int i;
+   UInt32 j, noRelocs;
 
    /* ToDo: should be variable-sized?  But is at least safe in the
       sense of buffer-overrun-proof. */
 
    /* ToDo: should be variable-sized?  But is at least safe in the
       sense of buffer-overrun-proof. */
@@ -1236,12 +1536,12 @@ ocResolve_PEi386 ( ObjectCode* oc )
 
    hdr = (COFF_header*)(oc->image);
    sectab = (COFF_section*) (
 
    hdr = (COFF_header*)(oc->image);
    sectab = (COFF_section*) (
-               ((UChar*)(oc->image)) 
+               ((UChar*)(oc->image))
                + sizeof_COFF_header + hdr->SizeOfOptionalHeader
             );
    symtab = (COFF_symbol*) (
                ((UChar*)(oc->image))
                + sizeof_COFF_header + hdr->SizeOfOptionalHeader
             );
    symtab = (COFF_symbol*) (
                ((UChar*)(oc->image))
-               + hdr->PointerToSymbolTable 
+               + hdr->PointerToSymbolTable
             );
    strtab = ((UChar*)(oc->image))
             + hdr->PointerToSymbolTable
             );
    strtab = ((UChar*)(oc->image))
             + hdr->PointerToSymbolTable
@@ -1255,16 +1555,40 @@ ocResolve_PEi386 ( ObjectCode* oc )
          = (COFF_reloc*) (
               ((UChar*)(oc->image)) + sectab_i->PointerToRelocations
            );
          = (COFF_reloc*) (
               ((UChar*)(oc->image)) + sectab_i->PointerToRelocations
            );
-      for (j = 0; j < sectab_i->NumberOfRelocations; j++) {
+
+      /* Ignore sections called which contain stabs debugging
+         information. */
+      if (0 == strcmp(".stab", sectab_i->Name)
+          || 0 == strcmp(".stabstr", sectab_i->Name))
+         continue;
+
+      if ( sectab_i->Characteristics & MYIMAGE_SCN_LNK_NRELOC_OVFL ) {
+       /* If the relocation field (a short) has overflowed, the
+        * real count can be found in the first reloc entry.
+         *
+        * See Section 4.1 (last para) of the PE spec (rev6.0).
+        */
+        COFF_reloc* rel = (COFF_reloc*)
+                           myindex ( sizeof_COFF_reloc, reltab, 0 );
+       noRelocs = rel->VirtualAddress;
+       fprintf(stderr, "Overflown relocs: %u\n", noRelocs);
+       j = 1;
+      } else {
+       noRelocs = sectab_i->NumberOfRelocations;
+        j = 0;
+      }
+
+
+      for (; j < noRelocs; j++) {
          COFF_symbol* sym;
          COFF_symbol* sym;
-         COFF_reloc* reltab_j 
+         COFF_reloc* reltab_j
             = (COFF_reloc*)
               myindex ( sizeof_COFF_reloc, reltab, j );
 
          /* the location to patch */
          pP = (UInt32*)(
             = (COFF_reloc*)
               myindex ( sizeof_COFF_reloc, reltab, j );
 
          /* the location to patch */
          pP = (UInt32*)(
-                 ((UChar*)(oc->image)) 
-                 + (sectab_i->PointerToRawData 
+                 ((UChar*)(oc->image))
+                 + (sectab_i->PointerToRawData
                     + reltab_j->VirtualAddress
                     - sectab_i->VirtualAddress )
               );
                     + reltab_j->VirtualAddress
                     - sectab_i->VirtualAddress )
               );
@@ -1272,24 +1596,23 @@ ocResolve_PEi386 ( ObjectCode* oc )
          A = *pP;
          /* the symbol to connect to */
          sym = (COFF_symbol*)
          A = *pP;
          /* the symbol to connect to */
          sym = (COFF_symbol*)
-               myindex ( sizeof_COFF_symbol, 
+               myindex ( sizeof_COFF_symbol,
                          symtab, reltab_j->SymbolTableIndex );
          IF_DEBUG(linker,
                          symtab, reltab_j->SymbolTableIndex );
          IF_DEBUG(linker,
-                  fprintf ( stderr, 
+                  fprintf ( stderr,
                             "reloc sec %2d num %3d:  type 0x%-4x   "
                             "vaddr 0x%-8x   name `",
                             i, j,
                             "reloc sec %2d num %3d:  type 0x%-4x   "
                             "vaddr 0x%-8x   name `",
                             i, j,
-                            (UInt32)reltab_j->Type, 
+                            (UInt32)reltab_j->Type,
                             reltab_j->VirtualAddress );
                             printName ( sym->Name, strtab );
                             fprintf ( stderr, "'\n" ));
 
          if (sym->StorageClass == MYIMAGE_SYM_CLASS_STATIC) {
                             reltab_j->VirtualAddress );
                             printName ( sym->Name, strtab );
                             fprintf ( stderr, "'\n" ));
 
          if (sym->StorageClass == MYIMAGE_SYM_CLASS_STATIC) {
-            COFF_section* section_sym 
+            COFF_section* section_sym
                = findPEi386SectionCalled ( oc, sym->Name );
             if (!section_sym) {
                = findPEi386SectionCalled ( oc, sym->Name );
             if (!section_sym) {
-               fprintf ( stderr, "bad section = `%s'\n", sym->Name );
-               barf("Can't find abovementioned PEi386 section");
+               belch("%s: can't find section `%s'", oc->fileName, sym->Name);
                return 0;
             }
             S = ((UInt32)(oc->image))
                return 0;
             }
             S = ((UInt32)(oc->image))
@@ -1297,20 +1620,23 @@ ocResolve_PEi386 ( ObjectCode* oc )
                    + sym->Value);
          } else {
             copyName ( sym->Name, strtab, symbol, 1000-1 );
                    + sym->Value);
          } else {
             copyName ( sym->Name, strtab, symbol, 1000-1 );
+            (void*)S = lookupLocalSymbol( oc, symbol );
+            if ((void*)S != NULL) goto foundit;
+            (void*)S = lookupSymbol( symbol );
+            if ((void*)S != NULL) goto foundit;
             zapTrailingAtSign ( symbol );
             (void*)S = lookupLocalSymbol( oc, symbol );
             zapTrailingAtSign ( symbol );
             (void*)S = lookupLocalSymbol( oc, symbol );
-            if ((void*)S == NULL)
-               (void*)S = lookupSymbol( symbol );
-            if (S == 0) {
-               belch("ocResolve_PEi386: %s: unknown symbol `%s'", 
-                      oc->fileName, symbol);
-               return 0;
-            }
+            if ((void*)S != NULL) goto foundit;
+            (void*)S = lookupSymbol( symbol );
+            if ((void*)S != NULL) goto foundit;
+            belch("%s: unknown symbol `%s'", oc->fileName, symbol);
+            return 0;
+           foundit:
          }
          }
-
+         checkProddableBlock(oc, pP);
          switch (reltab_j->Type) {
          switch (reltab_j->Type) {
-            case MYIMAGE_REL_I386_DIR32: 
-               *pP = A + S; 
+            case MYIMAGE_REL_I386_DIR32:
+               *pP = A + S;
                break;
             case MYIMAGE_REL_I386_REL32:
                /* Tricky.  We have to insert a displacement at
                break;
             case MYIMAGE_REL_I386_REL32:
                /* Tricky.  We have to insert a displacement at
@@ -1327,18 +1653,16 @@ ocResolve_PEi386 ( ObjectCode* oc )
                ASSERT(A==0);
                *pP = S - ((UInt32)pP) - 4;
                break;
                ASSERT(A==0);
                *pP = S - ((UInt32)pP) - 4;
                break;
-            default: 
-               fprintf(stderr, 
-                       "unhandled PEi386 relocation type %d\n",
-                       reltab_j->Type);
-               barf("unhandled PEi386 relocation type");
+            default:
+               belch("%s: unhandled PEi386 relocation type %d",
+                    oc->fileName, reltab_j->Type);
                return 0;
          }
 
       }
    }
                return 0;
          }
 
       }
    }
-   
-   /* fprintf(stderr, "completed     %s\n", oc->fileName); */
+
+   IF_DEBUG(linker, belch("completed %s", oc->fileName));
    return 1;
 }
 
    return 1;
 }
 
@@ -1356,21 +1680,33 @@ ocResolve_PEi386 ( ObjectCode* oc )
 
 #if defined(sparc_TARGET_ARCH)
 #  define ELF_TARGET_SPARC  /* Used inside <elf.h> */
 
 #if defined(sparc_TARGET_ARCH)
 #  define ELF_TARGET_SPARC  /* Used inside <elf.h> */
+#elif defined(i386_TARGET_ARCH)
+#  define ELF_TARGET_386    /* Used inside <elf.h> */
 #endif
 #endif
+/* There is a similar case for IA64 in the Solaris2 headers if this
+ * ever becomes relevant.
+ */
 
 #include <elf.h>
 
 #include <elf.h>
+#include <ctype.h>
 
 static char *
 findElfSection ( void* objImage, Elf32_Word sh_type )
 {
    int i;
    char* ehdrC = (char*)objImage;
 
 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);
+   Elf32_Ehdr* ehdr = (Elf32_Ehdr*)ehdrC;
+   Elf32_Shdr* shdr = (Elf32_Shdr*)(ehdrC + ehdr->e_shoff);
+   char* sh_strtab = ehdrC + shdr[ehdr->e_shstrndx].sh_offset;
    char* ptr = NULL;
    for (i = 0; i < ehdr->e_shnum; i++) {
    char* ptr = NULL;
    for (i = 0; i < ehdr->e_shnum; i++) {
-      if (shdr[i].sh_type == sh_type &&
-          i !=  ehdr->e_shstrndx) {
+      if (shdr[i].sh_type == sh_type
+          /* Ignore the section header's string table. */
+          && i != ehdr->e_shstrndx
+         /* Ignore string tables named .stabstr, as they contain
+             debugging info. */
+          && 0 != memcmp(".stabstr", sh_strtab + shdr[i].sh_name, 8)
+         ) {
          ptr = ehdrC + shdr[i].sh_offset;
          break;
       }
          ptr = ehdrC + shdr[i].sh_offset;
          break;
       }
@@ -1395,13 +1731,13 @@ ocVerifyImage_ELF ( ObjectCode* oc )
        ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
        ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
        ehdr->e_ident[EI_MAG3] != ELFMAG3) {
        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");
+      belch("%s: not an ELF header", oc->fileName);
       return 0;
    }
    IF_DEBUG(linker,belch( "Is an ELF header" ));
 
    if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) {
       return 0;
    }
    IF_DEBUG(linker,belch( "Is an ELF header" ));
 
    if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) {
-      belch("ocVerifyImage_ELF: not 32 bit ELF" );
+      belch("%s: not 32 bit ELF", oc->fileName);
       return 0;
    }
 
       return 0;
    }
 
@@ -1413,12 +1749,12 @@ ocVerifyImage_ELF ( ObjectCode* oc )
    if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) {
        IF_DEBUG(linker,belch( "Is big-endian" ));
    } else {
    if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) {
        IF_DEBUG(linker,belch( "Is big-endian" ));
    } else {
-       belch("ocVerifyImage_ELF: unknown endiannness");
+       belch("%s: unknown endiannness", oc->fileName);
        return 0;
    }
 
    if (ehdr->e_type != ET_REL) {
        return 0;
    }
 
    if (ehdr->e_type != ET_REL) {
-      belch("ocVerifyImage_ELF: not a relocatable object (.o) file");
+      belch("%s: not a relocatable object (.o) file", oc->fileName);
       return 0;
    }
    IF_DEBUG(linker, belch( "Is a relocatable object (.o) file" ));
       return 0;
    }
    IF_DEBUG(linker, belch( "Is a relocatable object (.o) file" ));
@@ -1427,13 +1763,13 @@ ocVerifyImage_ELF ( ObjectCode* oc )
    switch (ehdr->e_machine) {
       case EM_386:   IF_DEBUG(linker,belch( "x86" )); break;
       case EM_SPARC: IF_DEBUG(linker,belch( "sparc" )); break;
    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");
+      default:       IF_DEBUG(linker,belch( "unknown" ));
+                     belch("%s: unknown architecture", oc->fileName);
                      return 0;
    }
 
    IF_DEBUG(linker,belch(
                      return 0;
    }
 
    IF_DEBUG(linker,belch(
-             "\nSection header table: start %d, n_entries %d, ent_size %d", 
+             "\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));
              ehdr->e_shoff, ehdr->e_shnum, ehdr->e_shentsize  ));
 
    ASSERT (ehdr->e_shentsize == sizeof(Elf32_Shdr));
@@ -1441,10 +1777,10 @@ ocVerifyImage_ELF ( ObjectCode* oc )
    shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
 
    if (ehdr->e_shstrndx == SHN_UNDEF) {
    shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
 
    if (ehdr->e_shstrndx == SHN_UNDEF) {
-      belch("ocVerifyImage_ELF: no section header string table");
+      belch("%s: no section header string table", oc->fileName);
       return 0;
    } else {
       return 0;
    } else {
-      IF_DEBUG(linker,belch( "Section header string table is section %d", 
+      IF_DEBUG(linker,belch( "Section header string table is section %d",
                           ehdr->e_shstrndx));
       sh_strtab = ehdrC + shdr[ehdr->e_shstrndx].sh_offset;
    }
                           ehdr->e_shstrndx));
       sh_strtab = ehdrC + shdr[ehdr->e_shstrndx].sh_offset;
    }
@@ -1455,7 +1791,7 @@ ocVerifyImage_ELF ( ObjectCode* oc )
       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)  ",
       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,
                      ehdrC + shdr[i].sh_offset + shdr[i].sh_size - 1));
 
       if (shdr[i].sh_type == SHT_REL) {
                      ehdrC + shdr[i].sh_offset + shdr[i].sh_size - 1));
 
       if (shdr[i].sh_type == SHT_REL) {
@@ -1474,20 +1810,25 @@ ocVerifyImage_ELF ( ObjectCode* oc )
    strtab = NULL;
    nstrtab = 0;
    for (i = 0; i < ehdr->e_shnum; i++) {
    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 ));
+      if (shdr[i].sh_type == SHT_STRTAB
+          /* Ignore the section header's string table. */
+          && i != ehdr->e_shstrndx
+         /* Ignore string tables named .stabstr, as they contain
+             debugging info. */
+          && 0 != memcmp(".stabstr", sh_strtab + shdr[i].sh_name, 8)
+         ) {
+         IF_DEBUG(linker,belch("   section %d is a normal string table", i ));
          strtab = ehdrC + shdr[i].sh_offset;
          nstrtab++;
       }
          strtab = ehdrC + shdr[i].sh_offset;
          nstrtab++;
       }
-   }  
+   }
    if (nstrtab != 1) {
    if (nstrtab != 1) {
-      belch("ocVerifyImage_ELF: no string tables, or too many");
+      belch("%s: no string tables, or too many", oc->fileName);
       return 0;
    }
 
    nsymtabs = 0;
       return 0;
    }
 
    nsymtabs = 0;
-   IF_DEBUG(linker,belch( "\nSymbol tables" )); 
+   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 ));
    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 ));
@@ -1499,12 +1840,12 @@ ocVerifyImage_ELF ( ObjectCode* oc )
                shdr[i].sh_size % sizeof(Elf32_Sym)
              ));
       if (0 != shdr[i].sh_size % sizeof(Elf32_Sym)) {
                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");
+         belch("%s: non-integral number of symbol table entries", oc->fileName);
          return 0;
       }
       for (j = 0; j < nent; j++) {
          IF_DEBUG(linker,fprintf(stderr, "   %2d  ", j ));
          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  ", 
+         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 ));
                              (int)stab[j].st_shndx,
                              (int)stab[j].st_size,
                              (char*)stab[j].st_value ));
@@ -1534,7 +1875,7 @@ ocVerifyImage_ELF ( ObjectCode* oc )
    }
 
    if (nsymtabs == 0) {
    }
 
    if (nsymtabs == 0) {
-      belch("ocVerifyImage_ELF: didn't find any symbol tables");
+      belch("%s: didn't find any symbol tables", oc->fileName);
       return 0;
    }
 
       return 0;
    }
 
@@ -1552,37 +1893,68 @@ ocGetNames_ELF ( ObjectCode* oc )
    Elf32_Ehdr* ehdr       = (Elf32_Ehdr*)ehdrC;
    char*       strtab     = findElfSection ( ehdrC, SHT_STRTAB );
    Elf32_Shdr* shdr       = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
    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;
 
    ASSERT(symhash != NULL);
 
    if (!strtab) {
 
    ASSERT(symhash != NULL);
 
    if (!strtab) {
-      belch("ocGetNames_ELF: no strtab");
+      belch("%s: no strtab", oc->fileName);
       return 0;
    }
 
    k = 0;
       return 0;
    }
 
    k = 0;
-   oc->n_sections = ehdr->e_shnum;
-   oc->sections = stgMallocBytes( oc->n_sections * sizeof(Section), 
-                                  "ocGetNames_ELF(oc->sections)" );
-
-   for (i = 0; i < oc->n_sections; 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;
+   for (i = 0; i < ehdr->e_shnum; i++) {
+      /* Figure out what kind of section it is.  Logic derived from
+         Figure 1.14 ("Special Sections") of the ELF document
+         ("Portable Formats Specification, Version 1.1"). */
+      Elf32_Shdr  hdr    = shdr[i];
+      SectionKind kind   = SECTIONKIND_OTHER;
+      int         is_bss = FALSE;
+
+      if (hdr.sh_type == SHT_PROGBITS
+          && (hdr.sh_flags & SHF_ALLOC) && (hdr.sh_flags & SHF_EXECINSTR)) {
+         /* .text-style section */
+         kind = SECTIONKIND_CODE_OR_RODATA;
+      }
+      else
+      if (hdr.sh_type == SHT_PROGBITS
+          && (hdr.sh_flags & SHF_ALLOC) && (hdr.sh_flags & SHF_WRITE)) {
+         /* .data-style section */
+         kind = SECTIONKIND_RWDATA;
+      }
+      else
+      if (hdr.sh_type == SHT_PROGBITS
+          && (hdr.sh_flags & SHF_ALLOC) && !(hdr.sh_flags & SHF_WRITE)) {
+         /* .rodata-style section */
+         kind = SECTIONKIND_CODE_OR_RODATA;
+      }
+      else
+      if (hdr.sh_type == SHT_NOBITS
+          && (hdr.sh_flags & SHF_ALLOC) && (hdr.sh_flags & SHF_WRITE)) {
+         /* .bss-style section */
+         kind = SECTIONKIND_RWDATA;
+         is_bss = TRUE;
+      }
+
+      if (is_bss && shdr[i].sh_size > 0) {
+         /* This is a non-empty .bss section.  Allocate zeroed space for
+            it, and set its .sh_offset field such that
+            ehdrC + .sh_offset == addr_of_zeroed_space.  */
+         char* zspace = stgCallocBytes(1, shdr[i].sh_size,
+                                       "ocGetNames_ELF(BSS)");
+         shdr[i].sh_offset = ((char*)zspace) - ((char*)ehdrC);
+        /*
+         fprintf(stderr, "BSS section at 0x%x, size %d\n",
+                         zspace, shdr[i].sh_size);
+        */
+      }
 
       /* fill in the section info */
 
       /* 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 (kind != SECTIONKIND_OTHER && shdr[i].sh_size > 0) {
+         addProddableBlock(oc, ehdrC + shdr[i].sh_offset, shdr[i].sh_size);
+         addSection(oc, kind, ehdrC + shdr[i].sh_offset,
+                        ehdrC + shdr[i].sh_offset + shdr[i].sh_size - 1);
+      }
+
       if (shdr[i].sh_type != SHT_SYMTAB) continue;
 
       /* copy stuff into this module's object symbol table */
       if (shdr[i].sh_type != SHT_SYMTAB) continue;
 
       /* copy stuff into this module's object symbol table */
@@ -1590,10 +1962,30 @@ ocGetNames_ELF ( ObjectCode* oc )
       nent = shdr[i].sh_size / sizeof(Elf32_Sym);
 
       oc->n_symbols = nent;
       nent = shdr[i].sh_size / sizeof(Elf32_Sym);
 
       oc->n_symbols = nent;
-      oc->symbols = stgMallocBytes(oc->n_symbols * sizeof(char*), 
+      oc->symbols = stgMallocBytes(oc->n_symbols * sizeof(char*),
                                    "ocGetNames_ELF(oc->symbols)");
 
       for (j = 0; j < nent; j++) {
                                    "ocGetNames_ELF(oc->symbols)");
 
       for (j = 0; j < nent; j++) {
+
+         char  isLocal = FALSE; /* avoids uninit-var warning */
+         char* ad      = NULL;
+         char* nm      = strtab + stab[j].st_name;
+         int   secno   = stab[j].st_shndx;
+
+        /* Figure out if we want to add it; if so, set ad to its
+            address.  Otherwise leave ad == NULL. */
+
+         if (secno == SHN_COMMON) {
+            isLocal = FALSE;
+            ad = stgCallocBytes(1, stab[j].st_size, "ocGetNames_ELF(COMMON)");
+           /*
+            fprintf(stderr, "COMMON symbol, size %d name %s\n",
+                            stab[j].st_size, nm);
+           */
+           /* Pointless to do addProddableBlock() for this area,
+               since the linker should never poke around in it. */
+        }
+         else
          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
               )
@@ -1605,40 +1997,54 @@ ocGetNames_ELF ( ObjectCode* oc )
              /* 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 ||
              /* 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);
-           oc->symbols[j] = nm;
+            ) {
+           /* Section 0 is the undefined section, hence > and not >=. */
+            ASSERT(secno > 0 && secno < ehdr->e_shnum);
+           /*
+            if (shdr[secno].sh_type == SHT_NOBITS) {
+               fprintf(stderr, "   BSS symbol, size %d off %d name %s\n",
+                               stab[j].st_size, stab[j].st_value, nm);
+            }
+            */
+            ad = ehdrC + shdr[ secno ].sh_offset + stab[j].st_value;
             if (ELF32_ST_BIND(stab[j].st_info)==STB_LOCAL) {
             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, ad);
+               isLocal = TRUE;
             } else {
                IF_DEBUG(linker,belch( "addOTabName(GLOB): %10p  %s %s",
                                       ad, oc->fileName, nm ));
             } else {
                IF_DEBUG(linker,belch( "addOTabName(GLOB): %10p  %s %s",
                                       ad, oc->fileName, nm ));
-               insertStrHashTable(symhash, nm, ad);
+               isLocal = FALSE;
             }
          }
             }
          }
-         else {
-            IF_DEBUG(linker,belch( "skipping `%s'", 
+
+         /* And the decision is ... */
+
+         if (ad != NULL) {
+            ASSERT(nm != NULL);
+           oc->symbols[j] = nm;
+            /* Acquire! */
+            if (isLocal) {
+               /* Ignore entirely. */
+            } else {
+               ghciInsertStrHashTable(oc->fileName, symhash, nm, ad);
+            }
+         } else {
+            /* Skip. */
+            IF_DEBUG(linker,belch( "skipping `%s'",
                                    strtab + stab[j].st_name ));
             /*
                                    strtab + stab[j].st_name ));
             /*
-            fprintf(stderr, 
+            fprintf(stderr,
                     "skipping   bind = %d,  type = %d,  shndx = %d   `%s'\n",
                     "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)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] = NULL;
          }
                     (int)stab[j].st_shndx,
                     strtab + stab[j].st_name
                    );
             */
             oc->symbols[j] = NULL;
          }
+
       }
    }
 
       }
    }
 
@@ -1648,9 +2054,10 @@ ocGetNames_ELF ( ObjectCode* oc )
 
 /* Do ELF relocations which lack an explicit addend.  All x86-linux
    relocations appear to be of this form. */
 
 /* 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 )
+static int
+do_Elf32_Rel_relocations ( ObjectCode* oc, char* ehdrC,
+                           Elf32_Shdr* shdr, int shnum,
+                           Elf32_Sym*  stab, char* strtab )
 {
    int j;
    char *symbol;
 {
    int j;
    char *symbol;
@@ -1672,43 +2079,44 @@ static int do_Elf32_Rel_relocations ( ObjectCode* oc, char* ehdrC,
       Elf32_Addr  A  = *pP;
       Elf32_Addr  S;
 
       Elf32_Addr  A  = *pP;
       Elf32_Addr  S;
 
-      IF_DEBUG(linker,belch( "Rel entry %3d is raw(%6p %6p)", 
+      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 {
                              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)";
+         Elf32_Sym sym = stab[ELF32_R_SYM(info)];
+        /* First see if it is a local symbol. */
+         if (ELF32_ST_BIND(sym.st_info) == STB_LOCAL) {
+            /* Yes, so we can get the address directly from the ELF symbol
+               table. */
+            symbol = sym.st_name==0 ? "(noname)" : strtab+sym.st_name;
             S = (Elf32_Addr)
             S = (Elf32_Addr)
-                (ehdrC + shdr[stab[ELF32_R_SYM(info)].st_shndx ].sh_offset
+                (ehdrC + shdr[ sym.st_shndx ].sh_offset
                        + stab[ELF32_R_SYM(info)].st_value);
                        + 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 );
-         }
+
+        } else {
+            /* No, so look up the name in our global table. */
+            symbol = strtab + sym.st_name;
+            (void*)S = lookupSymbol( symbol );
+        }
          if (!S) {
          if (!S) {
-            barf("do_Elf32_Rel_relocations:  %s: unknown symbol `%s'", 
-                 oc->fileName, symbol);
+            belch("%s: unknown symbol `%s'", oc->fileName, symbol);
+           return 0;
          }
          IF_DEBUG(linker,belch( "`%s' resolves to %p", symbol, (void*)S ));
       }
       IF_DEBUG(linker,belch( "Reloc: P = %p   S = %p   A = %p",
          }
          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 )); 
+                            (void*)P, (void*)S, (void*)A ));
+      checkProddableBlock ( oc, pP );
       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
       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: 
-            fprintf(stderr, "unhandled ELF relocation(Rel) type %d\n",
-                            ELF32_R_TYPE(info));
-            barf("do_Elf32_Rel_relocations: unhandled ELF relocation type");
+         default:
+            belch("%s: unhandled ELF relocation(Rel) type %d\n",
+                 oc->fileName, ELF32_R_TYPE(info));
             return 0;
       }
 
             return 0;
       }
 
@@ -1719,9 +2127,10 @@ static int do_Elf32_Rel_relocations ( ObjectCode* oc, char* ehdrC,
 
 /* Do ELF relocations for which explicit addends are supplied.
    sparc-solaris relocations appear to be of this form. */
 
 /* 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 )
+static int
+do_Elf32_Rela_relocations ( ObjectCode* oc, char* ehdrC,
+                            Elf32_Shdr* shdr, int shnum,
+                            Elf32_Sym*  stab, char* strtab )
 {
    int j;
    char *symbol;
 {
    int j;
    char *symbol;
@@ -1737,10 +2146,11 @@ static int do_Elf32_Rela_relocations ( ObjectCode* oc, char* ehdrC,
    for (j = 0; j < nent; j++) {
       Elf32_Addr  offset = rtab[j].r_offset;
       Elf32_Word  info   = rtab[j].r_info;
    for (j = 0; j < nent; j++) {
       Elf32_Addr  offset = rtab[j].r_offset;
       Elf32_Word  info   = rtab[j].r_info;
+#     if defined(sparc_TARGET_ARCH) || defined(DEBUG)
       Elf32_Sword addend = rtab[j].r_addend;
       Elf32_Sword addend = rtab[j].r_addend;
-
-      Elf32_Addr  P  = ((Elf32_Addr)targ) + offset;
       Elf32_Addr  A  = addend;
       Elf32_Addr  A  = addend;
+#     endif
+      Elf32_Addr  P  = ((Elf32_Addr)targ) + offset;
       Elf32_Addr  S;
 #     if defined(sparc_TARGET_ARCH)
       /* This #ifdef only serves to avoid unused-var warnings. */
       Elf32_Addr  S;
 #     if defined(sparc_TARGET_ARCH)
       /* This #ifdef only serves to avoid unused-var warnings. */
@@ -1748,31 +2158,32 @@ static int do_Elf32_Rela_relocations ( ObjectCode* oc, char* ehdrC,
       Elf32_Word  w1, w2;
 #     endif
 
       Elf32_Word  w1, w2;
 #     endif
 
-      IF_DEBUG(linker,belch( "Rel entry %3d is raw(%6p %6p %6p)   ", 
-                             j, (void*)offset, (void*)info, 
+      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 {
                                 (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)";
+         Elf32_Sym sym = stab[ELF32_R_SYM(info)];
+        /* First see if it is a local symbol. */
+         if (ELF32_ST_BIND(sym.st_info) == STB_LOCAL) {
+            /* Yes, so we can get the address directly from the ELF symbol
+               table. */
+            symbol = sym.st_name==0 ? "(noname)" : strtab+sym.st_name;
             S = (Elf32_Addr)
             S = (Elf32_Addr)
-                (ehdrC + shdr[stab[ELF32_R_SYM(info)].st_shndx ].sh_offset
+                (ehdrC + shdr[ sym.st_shndx ].sh_offset
                        + stab[ELF32_R_SYM(info)].st_value);
                        + 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 );
-         }
+
+        } else {
+            /* No, so look up the name in our global table. */
+            symbol = strtab + sym.st_name;
+            (void*)S = lookupSymbol( symbol );
+        }
          if (!S) {
          if (!S) {
-          barf("do_Elf32_Rela_relocations: %s: unknown symbol `%s'", 
-                   oc->fileName, symbol);
-          /* 
+          belch("%s: unknown symbol `%s'", oc->fileName, symbol);
+          return 0;
+          /*
           S = 0x11223344;
           fprintf ( stderr, "S %p A %p S+A %p S+A-P %p\n",S,A,S+A,S+A-P);
           */
           S = 0x11223344;
           fprintf ( stderr, "S %p A %p S+A %p S+A-P %p\n",S,A,S+A,S+A-P);
           */
@@ -1780,10 +2191,11 @@ static int do_Elf32_Rela_relocations ( ObjectCode* oc, char* ehdrC,
          IF_DEBUG(linker,belch( "`%s' resolves to %p", symbol, (void*)S ));
       }
       IF_DEBUG(linker,fprintf ( stderr, "Reloc: P = %p   S = %p   A = %p\n",
          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 )); 
+                                        (void*)P, (void*)S, (void*)A ));
+      checkProddableBlock ( oc, (void*)P );
       switch (ELF32_R_TYPE(info)) {
 #        if defined(sparc_TARGET_ARCH)
       switch (ELF32_R_TYPE(info)) {
 #        if defined(sparc_TARGET_ARCH)
-         case R_SPARC_WDISP30: 
+         case R_SPARC_WDISP30:
             w1 = *pP & 0xC0000000;
             w2 = (Elf32_Word)((S + A - P) >> 2);
             ASSERT((w2 & 0xC0000000) == 0);
             w1 = *pP & 0xC0000000;
             w2 = (Elf32_Word)((S + A - P) >> 2);
             ASSERT((w2 & 0xC0000000) == 0);
@@ -1804,15 +2216,25 @@ static int do_Elf32_Rela_relocations ( ObjectCode* oc, char* ehdrC,
             w1 |= w2;
             *pP = w1;
             break;
             w1 |= w2;
             *pP = w1;
             break;
+         /* According to the Sun documentation:
+            R_SPARC_UA32
+            This relocation type resembles R_SPARC_32, except it refers to an
+            unaligned word. That is, the word to be relocated must be treated
+            as four separate bytes with arbitrary alignment, not as a word
+            aligned according to the architecture requirements.
+
+            (JRS: which means that freeloading on the R_SPARC_32 case
+            is probably wrong, but hey ...)
+         */
+         case R_SPARC_UA32:
          case R_SPARC_32:
             w2 = (Elf32_Word)(S + A);
             *pP = w2;
             break;
 #        endif
          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");
+         default:
+            belch("%s: unhandled ELF relocation(RelA) type %d\n",
+                 oc->fileName, ELF32_R_TYPE(info));
             return 0;
       }
 
             return 0;
       }
 
@@ -1830,6 +2252,7 @@ ocResolve_ELF ( ObjectCode* oc )
    char*       ehdrC = (char*)(oc->image);
    Elf32_Ehdr* ehdr = (Elf32_Ehdr*) ehdrC;
    Elf32_Shdr* shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
    char*       ehdrC = (char*)(oc->image);
    Elf32_Ehdr* ehdr = (Elf32_Ehdr*) ehdrC;
    Elf32_Shdr* shdr = (Elf32_Shdr*) (ehdrC + ehdr->e_shoff);
+   char* sh_strtab  = ehdrC + shdr[ehdr->e_shstrndx].sh_offset;
 
    /* first find "the" symbol table */
    stab = (Elf32_Sym*) findElfSection ( ehdrC, SHT_SYMTAB );
 
    /* first find "the" symbol table */
    stab = (Elf32_Sym*) findElfSection ( ehdrC, SHT_SYMTAB );
@@ -1838,23 +2261,32 @@ ocResolve_ELF ( ObjectCode* oc )
    strtab = findElfSection ( ehdrC, SHT_STRTAB );
 
    if (stab == NULL || strtab == NULL) {
    strtab = findElfSection ( ehdrC, SHT_STRTAB );
 
    if (stab == NULL || strtab == NULL) {
-      belch("ocResolve_ELF: can't find string or symbol table");
-      return 0; 
+      belch("%s: can't find string or symbol table", oc->fileName);
+      return 0;
    }
 
    /* Process the relocation sections. */
    for (shnum = 0; shnum < ehdr->e_shnum; shnum++) {
    }
 
    /* Process the relocation sections. */
    for (shnum = 0; shnum < ehdr->e_shnum; shnum++) {
+
+      /* Skip sections called ".rel.stab".  These appear to contain
+         relocation entries that, when done, make the stabs debugging
+         info point at the right places.  We ain't interested in all
+         dat jazz, mun. */
+      if (0 == memcmp(".rel.stab", sh_strtab + shdr[shnum].sh_name, 9))
+         continue;
+
       if (shdr[shnum].sh_type == SHT_REL ) {
       if (shdr[shnum].sh_type == SHT_REL ) {
-         ok = do_Elf32_Rel_relocations ( oc, ehdrC, shdr, 
+         ok = do_Elf32_Rel_relocations ( oc, ehdrC, shdr,
                                          shnum, stab, strtab );
          if (!ok) return ok;
       }
       else
       if (shdr[shnum].sh_type == SHT_RELA) {
                                          shnum, stab, strtab );
          if (!ok) return ok;
       }
       else
       if (shdr[shnum].sh_type == SHT_RELA) {
-         ok = do_Elf32_Rela_relocations ( oc, ehdrC, shdr, 
+         ok = do_Elf32_Rela_relocations ( oc, ehdrC, shdr,
                                           shnum, stab, strtab );
          if (!ok) return ok;
       }
                                           shnum, stab, strtab );
          if (!ok) return ok;
       }
+
    }
 
    /* Free the local symbol table; we won't need it again. */
    }
 
    /* Free the local symbol table; we won't need it again. */