[project @ 2004-11-19 18:00:29 by simonpj]
[ghc-hetmet.git] / ghc / rts / Linker.c
index f27f144..d8f1e43 100644 (file)
@@ -1,7 +1,6 @@
 /* -----------------------------------------------------------------------------
- * $Id: Linker.c,v 1.108 2002/12/19 14:33:22 simonmar Exp $
  *
- * (c) The GHC Team, 2000, 2001
+ * (c) The GHC Team, 2000-2004
  *
  * RTS Object Linker
  *
@@ -10,6 +9,12 @@
 #if 0
 #include "PosixSource.h"
 #endif
+
+//  Linux needs _GNU_SOURCE to get RTLD_DEFAULT from <dlfcn.h>.
+#ifdef __linux__
+#define _GNU_SOURCE
+#endif
+
 #include "Rts.h"
 #include "RtsFlags.h"
 #include "HsFFI.h"
@@ -17,8 +22,8 @@
 #include "Linker.h"
 #include "LinkerInternals.h"
 #include "RtsUtils.h"
-#include "StoragePriv.h"
 #include "Schedule.h"
+#include "Storage.h"
 
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #include <sys/wait.h>
 #endif
 
-#if defined(ia64_TARGET_ARCH)
+#if defined(ia64_TARGET_ARCH) || defined(openbsd_TARGET_OS)
 #define USE_MMAP
 #include <fcntl.h>
 #include <sys/mman.h>
+
+#if defined(openbsd_TARGET_OS) 
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#endif
+
 #endif
 
-#if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS) || defined(freebsd_TARGET_OS)
+#if defined(linux_TARGET_OS) || defined(solaris2_TARGET_OS) || defined(freebsd_TARGET_OS) || defined(netbsd_TARGET_OS) || defined(openbsd_TARGET_OS)
 #  define OBJFORMAT_ELF
 #elif defined(cygwin32_TARGET_OS) || defined (mingw32_TARGET_OS)
 #  define OBJFORMAT_PEi386
@@ -71,6 +83,7 @@
 #  include <mach-o/loader.h>
 #  include <mach-o/nlist.h>
 #  include <mach-o/reloc.h>
+#  include <mach-o/dyld.h>
 #endif
 
 /* Hash table mapping symbol names to Symbol */
@@ -83,14 +96,20 @@ ObjectCode *objects = NULL; /* initially empty */
 static int ocVerifyImage_ELF    ( ObjectCode* oc );
 static int ocGetNames_ELF       ( ObjectCode* oc );
 static int ocResolve_ELF        ( ObjectCode* oc );
+#if defined(powerpc_TARGET_ARCH)
+static int ocAllocateJumpIslands_ELF ( ObjectCode* oc );
+#endif
 #elif defined(OBJFORMAT_PEi386)
 static int ocVerifyImage_PEi386 ( ObjectCode* oc );
 static int ocGetNames_PEi386    ( ObjectCode* oc );
 static int ocResolve_PEi386     ( ObjectCode* oc );
 #elif defined(OBJFORMAT_MACHO)
+static int ocAllocateJumpIslands_MachO ( ObjectCode* oc );
 static int ocVerifyImage_MachO    ( ObjectCode* oc );
 static int ocGetNames_MachO       ( ObjectCode* oc );
 static int ocResolve_MachO        ( ObjectCode* oc );
+
+static void machoInitSymbolsWithoutUnderscore( void );
 #endif
 
 /* -----------------------------------------------------------------------------
@@ -125,7 +144,7 @@ typedef struct _RtsSymbolVal {
 #define RTS_MINGW_ONLY_SYMBOLS /**/
 /* Don't have the ability to read import libs / archives, so
  * we have to stupidly list a lot of what libcygwin.a
- * exports; sigh. 
+ * exports; sigh.
  */
 #define RTS_CYGWIN_ONLY_SYMBOLS                 \
       SymX(regfree)                             \
@@ -203,11 +222,7 @@ typedef struct _RtsSymbolVal {
       SymX(uname)                               \
       SymX(unlink)                              \
       SymX(utime)                               \
-      SymX(waitpid)                             \
-      Sym(__divdi3)                             \
-      Sym(__udivdi3)                            \
-      Sym(__moddi3)                             \
-      Sym(__umoddi3)
+      SymX(waitpid)
 
 #elif !defined(mingw32_TARGET_OS)
 #define RTS_MINGW_ONLY_SYMBOLS /**/
@@ -216,9 +231,21 @@ typedef struct _RtsSymbolVal {
 #define RTS_POSIX_ONLY_SYMBOLS  /**/
 #define RTS_CYGWIN_ONLY_SYMBOLS /**/
 
+/* Extra syms gen'ed by mingw-2's gcc-3.2: */
+#if __GNUC__>=3
+#define RTS_MINGW_EXTRA_SYMS                    \
+      Sym(_imp____mb_cur_max)                   \
+      Sym(_imp___pctype)
+#else
+#define RTS_MINGW_EXTRA_SYMS
+#endif
+
 /* 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(asyncReadzh_fast)                   \
+      SymX(asyncWritezh_fast)                  \
+      SymX(asyncDoProczh_fast)                 \
       SymX(memset)                              \
       SymX(inet_ntoa)                           \
       SymX(inet_addr)                           \
@@ -269,6 +296,7 @@ typedef struct _RtsSymbolVal {
       SymX(log)                                 \
       SymX(sqrt)                                \
       SymX(memcpy)                              \
+      SymX(stg_InstallConsoleEvent)             \
       Sym(mktime)                               \
       Sym(_imp___timezone)                      \
       Sym(_imp___tzname)                        \
@@ -278,11 +306,8 @@ typedef struct _RtsSymbolVal {
       Sym(opendir)                              \
       Sym(readdir)                              \
       Sym(rewinddir)                            \
-      Sym(closedir)                             \
-      Sym(__divdi3)                             \
-      Sym(__udivdi3)                            \
-      Sym(__moddi3)                             \
-      Sym(__umoddi3)
+      RTS_MINGW_EXTRA_SYMS                      \
+      Sym(closedir)
 #endif
 
 #ifndef SMP
@@ -291,13 +316,34 @@ typedef struct _RtsSymbolVal {
 # define MAIN_CAP_SYM
 #endif
 
+#ifdef TABLES_NEXT_TO_CODE
+#define RTS_RET_SYMBOLS /* nothing */
+#else
+#define RTS_RET_SYMBOLS                        \
+      SymX(stg_enter_ret)                      \
+      SymX(stg_gc_fun_ret)                     \
+      SymX(stg_ap_0_ret)                       \
+      SymX(stg_ap_v_ret)                       \
+      SymX(stg_ap_f_ret)                       \
+      SymX(stg_ap_d_ret)                       \
+      SymX(stg_ap_l_ret)                       \
+      SymX(stg_ap_n_ret)                       \
+      SymX(stg_ap_p_ret)                       \
+      SymX(stg_ap_pv_ret)                      \
+      SymX(stg_ap_pp_ret)                      \
+      SymX(stg_ap_ppv_ret)                     \
+      SymX(stg_ap_ppp_ret)                     \
+      SymX(stg_ap_pppv_ret)                    \
+      SymX(stg_ap_pppp_ret)                    \
+      SymX(stg_ap_ppppp_ret)                   \
+      SymX(stg_ap_pppppp_ret)
+#endif
+
 #define RTS_SYMBOLS                            \
       Maybe_ForeignObj                         \
       Maybe_Stable_Names                       \
       Sym(StgReturn)                           \
-      Sym(init_stack)                          \
       SymX(stg_enter_info)                     \
-      SymX(stg_enter_ret)                      \
       SymX(stg_gc_void_info)                   \
       SymX(__stg_gc_enter_1)                   \
       SymX(stg_gc_noregs)                      \
@@ -313,7 +359,6 @@ typedef struct _RtsSymbolVal {
       SymX(stg_gc_l1)                          \
       SymX(__stg_gc_fun)                       \
       SymX(stg_gc_fun_info)                    \
-      SymX(stg_gc_fun_ret)                     \
       SymX(stg_gc_gen)                         \
       SymX(stg_gc_gen_info)                    \
       SymX(stg_gc_gen_hp)                      \
@@ -327,18 +372,14 @@ typedef struct _RtsSymbolVal {
       SymX(stg_block_takemvar)                 \
       SymX(stg_block_putmvar)                  \
       SymX(stg_seq_frame_info)                 \
-      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(addDLL)                             \
       SymX(__gmpn_gcd_1)                       \
       SymX(__gmpz_cmp)                         \
       SymX(__gmpz_cmp_si)                      \
@@ -348,12 +389,17 @@ typedef struct _RtsSymbolVal {
       SymX(__int_encodeDouble)                 \
       SymX(__int_encodeFloat)                  \
       SymX(andIntegerzh_fast)                  \
+      SymX(atomicallyzh_fast)                  \
+      SymX(barf)                               \
       SymX(blockAsyncExceptionszh_fast)                \
       SymX(catchzh_fast)                       \
+      SymX(catchRetryzh_fast)                  \
+      SymX(catchSTMzh_fast)                    \
+      SymX(closure_flags)                       \
       SymX(cmp_thread)                         \
-      SymX(complementIntegerzh_fast)           \
       SymX(cmpIntegerzh_fast)                  \
       SymX(cmpIntegerIntzh_fast)               \
+      SymX(complementIntegerzh_fast)           \
       SymX(createAdjustor)                     \
       SymX(decodeDoublezh_fast)                        \
       SymX(decodeFloatzh_fast)                 \
@@ -364,17 +410,22 @@ typedef struct _RtsSymbolVal {
       SymX(divExactIntegerzh_fast)             \
       SymX(divModIntegerzh_fast)               \
       SymX(forkzh_fast)                                \
-      SymX(forkProcesszh_fast)                  \
+      SymX(forkProcess)                                \
+      SymX(forkOS_createThread)                        \
       SymX(freeHaskellFunctionPtr)             \
       SymX(freeStablePtr)                      \
       SymX(gcdIntegerzh_fast)                  \
       SymX(gcdIntegerIntzh_fast)               \
       SymX(gcdIntzh_fast)                      \
+      SymX(genSymZh)                           \
+      SymX(genericRaise)                       \
       SymX(getProgArgv)                                \
       SymX(getStablePtr)                       \
+      SymX(initLinker)                         \
       SymX(int2Integerzh_fast)                 \
       SymX(integer2Intzh_fast)                 \
       SymX(integer2Wordzh_fast)                        \
+      SymX(isCurrentThreadBoundzh_fast)                \
       SymX(isDoubleDenormalized)               \
       SymX(isDoubleInfinite)                   \
       SymX(isDoubleNaN)                                \
@@ -385,6 +436,8 @@ typedef struct _RtsSymbolVal {
       SymX(isFloatNaN)                         \
       SymX(isFloatNegativeZero)                        \
       SymX(killThreadzh_fast)                  \
+      SymX(loadObj)                            \
+      SymX(lookupSymbol)                       \
       SymX(makeStablePtrzh_fast)               \
       SymX(minusIntegerzh_fast)                        \
       SymX(mkApUpd0zh_fast)                    \
@@ -396,10 +449,12 @@ typedef struct _RtsSymbolVal {
       SymX_redirect(newCAF, newDynCAF)         \
       SymX(newMVarzh_fast)                     \
       SymX(newMutVarzh_fast)                   \
+      SymX(newTVarzh_fast)                     \
       SymX(atomicModifyMutVarzh_fast)          \
       SymX(newPinnedByteArrayzh_fast)          \
       SymX(orIntegerzh_fast)                   \
       SymX(performGC)                          \
+      SymX(performMajorGC)                     \
       SymX(plusIntegerzh_fast)                 \
       SymX(prog_argc)                          \
       SymX(prog_argv)                          \
@@ -407,14 +462,19 @@ typedef struct _RtsSymbolVal {
       SymX(quotIntegerzh_fast)                 \
       SymX(quotRemIntegerzh_fast)              \
       SymX(raisezh_fast)                       \
+      SymX(raiseIOzh_fast)                     \
+      SymX(readTVarzh_fast)                    \
       SymX(remIntegerzh_fast)                  \
       SymX(resetNonBlockingFd)                 \
       SymX(resumeThread)                       \
+      SymX(resolveObjs)                         \
+      SymX(retryzh_fast)                        \
       SymX(rts_apply)                          \
       SymX(rts_checkSchedStatus)               \
       SymX(rts_eval)                           \
       SymX(rts_evalIO)                         \
       SymX(rts_evalLazyIO)                     \
+      SymX(rts_evalStableIO)                   \
       SymX(rts_eval_)                          \
       SymX(rts_getBool)                                \
       SymX(rts_getChar)                                \
@@ -423,10 +483,12 @@ typedef struct _RtsSymbolVal {
       SymX(rts_getInt)                         \
       SymX(rts_getInt32)                       \
       SymX(rts_getPtr)                         \
+      SymX(rts_getFunPtr)                      \
       SymX(rts_getStablePtr)                   \
       SymX(rts_getThreadId)                    \
       SymX(rts_getWord)                                \
       SymX(rts_getWord32)                      \
+      SymX(rts_lock)                           \
       SymX(rts_mkBool)                         \
       SymX(rts_mkChar)                         \
       SymX(rts_mkDouble)                       \
@@ -437,6 +499,7 @@ typedef struct _RtsSymbolVal {
       SymX(rts_mkInt64)                                \
       SymX(rts_mkInt8)                         \
       SymX(rts_mkPtr)                          \
+      SymX(rts_mkFunPtr)                       \
       SymX(rts_mkStablePtr)                    \
       SymX(rts_mkString)                       \
       SymX(rts_mkWord)                         \
@@ -444,18 +507,27 @@ typedef struct _RtsSymbolVal {
       SymX(rts_mkWord32)                       \
       SymX(rts_mkWord64)                       \
       SymX(rts_mkWord8)                                \
+      SymX(rts_unlock)                         \
+      SymX(rtsSupportsBoundThreads)            \
       SymX(run_queue_hd)                       \
+      SymX(__hscore_get_saved_termios)         \
+      SymX(__hscore_set_saved_termios)         \
       SymX(setProgArgv)                                \
+      SymX(startupHaskell)                     \
+      SymX(shutdownHaskell)                    \
       SymX(shutdownHaskellAndExit)             \
       SymX(stable_ptr_table)                   \
       SymX(stackOverflow)                      \
       SymX(stg_CAF_BLACKHOLE_info)             \
+      SymX(stg_BLACKHOLE_BQ_info)              \
+      SymX(awakenBlockedQueue)                 \
       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_0_info)                      \
       SymX(stg_ap_v_info)                      \
       SymX(stg_ap_f_info)                      \
       SymX(stg_ap_d_info)                      \
@@ -466,25 +538,10 @@ typedef struct _RtsSymbolVal {
       SymX(stg_ap_pp_info)                     \
       SymX(stg_ap_ppv_info)                    \
       SymX(stg_ap_ppp_info)                    \
+      SymX(stg_ap_pppv_info)                   \
       SymX(stg_ap_pppp_info)                   \
       SymX(stg_ap_ppppp_info)                  \
       SymX(stg_ap_pppppp_info)                 \
-      SymX(stg_ap_ppppppp_info)                        \
-      SymX(stg_ap_0_ret)                       \
-      SymX(stg_ap_v_ret)                       \
-      SymX(stg_ap_f_ret)                       \
-      SymX(stg_ap_d_ret)                       \
-      SymX(stg_ap_l_ret)                       \
-      SymX(stg_ap_n_ret)                       \
-      SymX(stg_ap_p_ret)                       \
-      SymX(stg_ap_pv_ret)                      \
-      SymX(stg_ap_pp_ret)                      \
-      SymX(stg_ap_ppv_ret)                     \
-      SymX(stg_ap_ppp_ret)                     \
-      SymX(stg_ap_pppp_ret)                    \
-      SymX(stg_ap_ppppp_ret)                   \
-      SymX(stg_ap_pppppp_ret)                  \
-      SymX(stg_ap_ppppppp_ret)                 \
       SymX(stg_ap_1_upd_info)                  \
       SymX(stg_ap_2_upd_info)                  \
       SymX(stg_ap_3_upd_info)                  \
@@ -492,7 +549,6 @@ typedef struct _RtsSymbolVal {
       SymX(stg_ap_5_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_10_upd_info)                        \
@@ -517,10 +573,12 @@ typedef struct _RtsSymbolVal {
       SymX(tryPutMVarzh_fast)                  \
       SymX(tryTakeMVarzh_fast)                 \
       SymX(unblockAsyncExceptionszh_fast)      \
+      SymX(unloadObj)                           \
       SymX(unsafeThawArrayzh_fast)             \
       SymX(waitReadzh_fast)                    \
       SymX(waitWritezh_fast)                   \
       SymX(word2Integerzh_fast)                        \
+      SymX(writeTVarzh_fast)                   \
       SymX(xorIntegerzh_fast)                  \
       SymX(yieldzh_fast)
 
@@ -532,12 +590,9 @@ typedef struct _RtsSymbolVal {
 #define RTS_LONG_LONG_SYMS /* nothing */
 #endif
 
-#ifdef ia64_TARGET_ARCH
-/* force these symbols to be present */
-#define RTS_EXTRA_SYMBOLS                      \
-      Sym(__divsf3)
-#elif defined(powerpc_TARGET_ARCH)
-#define RTS_EXTRA_SYMBOLS                      \
+// 64-bit support functions in libgcc.a
+#if defined(__GNUC__) && SIZEOF_VOID_P <= 4
+#define RTS_LIBGCC_SYMBOLS                     \
       Sym(__divdi3)                             \
       Sym(__udivdi3)                            \
       Sym(__moddi3)                             \
@@ -546,22 +601,41 @@ typedef struct _RtsSymbolVal {
       Sym(__ashrdi3)                           \
       Sym(__lshrdi3)                           \
       Sym(__eprintf)
+#elif defined(ia64_TARGET_ARCH)
+#define RTS_LIBGCC_SYMBOLS                     \
+      Sym(__divdi3)                            \
+      Sym(__udivdi3)                            \
+      Sym(__moddi3)                            \
+      Sym(__umoddi3)                           \
+      Sym(__divsf3)                            \
+      Sym(__divdf3)
 #else
-#define RTS_EXTRA_SYMBOLS /* nothing */
+#define RTS_LIBGCC_SYMBOLS
+#endif
+
+#ifdef darwin_TARGET_OS
+      // Symbols that don't have a leading underscore
+      // on Mac OS X. They have to receive special treatment,
+      // see machoInitSymbolsWithoutUnderscore()
+#define RTS_MACHO_NOUNDERLINE_SYMBOLS          \
+      Sym(saveFP)                              \
+      Sym(restFP)
 #endif
 
 /* entirely bogus claims about types of these symbols */
-#define Sym(vvv)  extern void (vvv);
+#define Sym(vvv)  extern void vvv(void);
 #define SymX(vvv) /**/
 #define SymX_redirect(vvv,xxx) /**/
 RTS_SYMBOLS
+RTS_RET_SYMBOLS
 RTS_LONG_LONG_SYMS
-RTS_EXTRA_SYMBOLS
 RTS_POSIX_ONLY_SYMBOLS
 RTS_MINGW_ONLY_SYMBOLS
 RTS_CYGWIN_ONLY_SYMBOLS
+RTS_LIBGCC_SYMBOLS
 #undef Sym
 #undef SymX
+#undef SymX_redirect
 
 #ifdef LEADING_UNDERSCORE
 #define MAYBE_LEADING_UNDERSCORE_STR(s) ("_" s)
@@ -581,11 +655,12 @@ RTS_CYGWIN_ONLY_SYMBOLS
 
 static RtsSymbolVal rtsSyms[] = {
       RTS_SYMBOLS
+      RTS_RET_SYMBOLS
       RTS_LONG_LONG_SYMS
-      RTS_EXTRA_SYMBOLS
       RTS_POSIX_ONLY_SYMBOLS
       RTS_MINGW_ONLY_SYMBOLS
       RTS_CYGWIN_ONLY_SYMBOLS
+      RTS_LIBGCC_SYMBOLS
       { 0, 0 } /* sentinel */
 };
 
@@ -603,7 +678,7 @@ static void ghciInsertStrHashTable ( char* obj_name,
       insertStrHashTable(table, (StgWord)key, data);
       return;
    }
-   fprintf(stderr,
+   debugBelch(
       "\n\n"
       "GHCi runtime linker: fatal error: I found a duplicate definition for symbol\n"
       "   %s\n"
@@ -634,6 +709,11 @@ static int linker_init_done = 0 ;
 static void *dl_prog_handle;
 #endif
 
+/* dlopen(NULL,..) doesn't work so we grab libc explicitly */
+#if defined(openbsd_TARGET_OS)
+static void *dl_libc_handle;
+#endif
+
 void
 initLinker( void )
 {
@@ -653,8 +733,19 @@ initLinker( void )
        ghciInsertStrHashTable("(GHCi built-in symbols)",
                                symhash, sym->lbl, sym->addr);
     }
+#   if defined(OBJFORMAT_MACHO)
+    machoInitSymbolsWithoutUnderscore();
+#   endif
+
 #   if defined(OBJFORMAT_ELF) || defined(OBJFORMAT_MACHO)
+#   if defined(RTLD_DEFAULT)
+    dl_prog_handle = RTLD_DEFAULT;
+#   else
     dl_prog_handle = dlopen(NULL, RTLD_LAZY);
+#   if defined(openbsd_TARGET_OS)
+    dl_libc_handle = dlopen("libc.so", RTLD_LAZY);
+#   endif
+#   endif // RTLD_DEFAULT
 #   endif
 }
 
@@ -675,7 +766,7 @@ initLinker( void )
  * to give to loadSymbol, so that we can find the symbols.  For such
  * libraries, the LoadLibrary call should be a no-op except for returning
  * the handle.
- * 
+ *
  */
 
 #if defined(OBJFORMAT_PEi386)
@@ -704,6 +795,7 @@ addDLL( char *dll_name )
    initLinker();
 
    hdl= dlopen(dll_name, RTLD_NOW | RTLD_GLOBAL);
+
    if (hdl == NULL) {
       /* dlopen failed; return a ptr to the error msg. */
       errmsg = dlerror();
@@ -723,7 +815,7 @@ addDLL( char *dll_name )
 
    initLinker();
 
-   /* fprintf(stderr, "\naddDLL; dll_name = `%s'\n", dll_name); */
+   /* debugBelch("\naddDLL; dll_name = `%s'\n", dll_name); */
 
    /* See if we've already got it, and ignore if so. */
    for (o_dll = opened_dlls; o_dll != NULL; o_dll = o_dll->next) {
@@ -748,13 +840,13 @@ addDLL( char *dll_name )
         sprintf(buf, "%s.DRV", dll_name);      // KAA: allow loading of drivers (like winspool.drv)
         instance = LoadLibrary(buf);
         if (instance == NULL) {
-               free(buf);
+               stgFree(buf);
 
            /* LoadLibrary failed; return a ptr to the error msg. */
            return "addDLL: unknown error";
         }
    }
-   free(buf);
+   stgFree(buf);
 
    /* Add this DLL to the list of DLLs in which to search for symbols. */
    o_dll = stgMallocBytes( sizeof(OpenedDLL), "addDLL" );
@@ -782,13 +874,25 @@ lookupSymbol( char *lbl )
     val = lookupStrHashTable(symhash, lbl);
 
     if (val == NULL) {
-#       if defined(OBJFORMAT_ELF) || defined(OBJFORMAT_MACHO)
+#       if defined(OBJFORMAT_ELF)
+#      if defined(openbsd_TARGET_OS)
+       val = dlsym(dl_prog_handle, lbl);
+       return (val != NULL) ? val : dlsym(dl_libc_handle,lbl);
+#      else /* not openbsd */
        return dlsym(dl_prog_handle, lbl);
+#      endif
+#       elif defined(OBJFORMAT_MACHO)
+       if(NSIsSymbolNameDefined(lbl)) {
+           NSSymbol symbol = NSLookupAndBindSymbol(lbl);
+           return NSAddressOfSymbol(symbol);
+       } else {
+           return NULL;
+       }
 #       elif defined(OBJFORMAT_PEi386)
         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); */
+         /* debugBelch("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
@@ -797,13 +901,13 @@ lookupSymbol( char *lbl )
               */
               sym = GetProcAddress(o_dll->instance, (lbl+1));
               if (sym != NULL) {
-               /*fprintf(stderr, "found %s in %s\n", lbl+1,o_dll->name); fflush(stderr);*/
+               /*debugBelch("found %s in %s\n", lbl+1,o_dll->name);*/
                return sym;
              }
            }
            sym = GetProcAddress(o_dll->instance, lbl);
            if (sym != NULL) {
-            /*fprintf(stderr, "found %s in %s\n", lbl,o_dll->name); fflush(stderr);*/
+            /*debugBelch("found %s in %s\n", lbl,o_dll->name);*/
             return sym;
           }
         }
@@ -855,7 +959,7 @@ void ghci_enquire ( char* addr )
       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);
+         // debugBelch("enquire %p %p\n", sym, oc->lochash);
          a = NULL;
          if (oc->lochash != NULL) {
             a = lookupStrHashTable(oc->lochash, sym);
@@ -864,10 +968,10 @@ void ghci_enquire ( char* addr )
             a = lookupStrHashTable(symhash, sym);
         }
          if (a == NULL) {
-            // fprintf(stderr, "ghci_enquire: can't find %s\n", sym);
+            // debugBelch("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);
+            debugBelch("%p + %3d  ==  `%s'\n", addr, a - addr, sym);
          }
       }
    }
@@ -891,33 +995,34 @@ loadObj( char *path )
    int r, n;
 #ifdef USE_MMAP
    int fd, pagesize;
-   void *map_addr;
+   void *map_addr = NULL;
 #else
    FILE *f;
 #endif
 
    initLinker();
 
-   /* fprintf(stderr, "loadObj %s\n", path ); */
+   /* debugBelch("loadObj %s\n", path ); */
 
-   /* Check that we haven't already loaded this object.  Don't give up
-      at this stage; ocGetNames_* will barf later. */
+   /* Check that we haven't already loaded this object. 
+      Ignore requests to load multiple times */
    {
        ObjectCode *o;
        int is_dup = 0;
        for (o = objects; o; o = o->next) {
-          if (0 == strcmp(o->fileName, path))
+          if (0 == strcmp(o->fileName, path)) {
              is_dup = 1;
+             break; /* don't need to search further */
+          }
        }
        if (is_dup) {
-        fprintf(stderr,
-            "\n\n"
+          IF_DEBUG(linker, debugBelch(
             "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);
+            "GHCi will ignore this, but be warned.\n"
+            , path));
+          return 1; /* success */
        }
    }
 
@@ -930,7 +1035,7 @@ loadObj( char *path )
 #  elif defined(OBJFORMAT_MACHO)
    oc->formatName = "Mach-O";
 #  else
-   free(oc);
+   stgFree(oc);
    barf("loadObj: not implemented on this platform");
 #  endif
 
@@ -956,7 +1061,11 @@ loadObj( char *path )
 
    /* On many architectures malloc'd memory isn't executable, so we need to use mmap. */
 
+#if defined(openbsd_TARGET_OS)
+   fd = open(path, O_RDONLY, S_IRUSR);
+#else
    fd = open(path, O_RDONLY);
+#endif
    if (fd == -1)
       barf("loadObj: can't open `%s'", path);
 
@@ -997,6 +1106,14 @@ loadObj( char *path )
 
 #endif /* USE_MMAP */
 
+#  if defined(OBJFORMAT_MACHO)
+   r = ocAllocateJumpIslands_MachO ( oc );
+   if (!r) { return r; }
+#  elif defined(OBJFORMAT_ELF) && defined(powerpc_TARGET_ARCH)
+   r = ocAllocateJumpIslands_ELF ( oc );
+   if (!r) { return r; }
+#endif
+
    /* verify the in-memory image */
 #  if defined(OBJFORMAT_ELF)
    r = ocVerifyImage_ELF ( oc );
@@ -1069,7 +1186,7 @@ unloadObj( char *path )
     ASSERT(symhash != NULL);
     ASSERT(objects != NULL);
 
-    initLinker(); 
+    initLinker();
 
     prev = NULL;
     for (oc = objects; oc; prev = oc, oc = oc->next) {
@@ -1095,19 +1212,19 @@ unloadObj( char *path )
 
            /* We're going to leave this in place, in case there are
               any pointers from the heap into it: */
-           /* free(oc->image); */
-           free(oc->fileName);
-           free(oc->symbols);
-           free(oc->sections);
+           /* stgFree(oc->image); */
+           stgFree(oc->fileName);
+           stgFree(oc->symbols);
+           stgFree(oc->sections);
            /* The local hash table should have been freed at the end
                of the ocResolve_ call on it. */
             ASSERT(oc->lochash == NULL);
-           free(oc);
+           stgFree(oc);
            return 1;
        }
     }
 
-    belch("unloadObj: can't find `%s' to unload", path);
+    errorBelch("unloadObj: can't find `%s' to unload", path);
     return 0;
 }
 
@@ -1120,7 +1237,7 @@ 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); */
+   /* debugBelch("aPB %p %p %d\n", oc, start, size); */
    ASSERT(size > 0);
    pb->start      = start;
    pb->size       = size;
@@ -1156,12 +1273,118 @@ static void addSection ( ObjectCode* oc, SectionKind kind,
    s->next      = oc->sections;
    oc->sections = s;
    /*
-   fprintf(stderr, "addSection: %p-%p (size %d), kind %d\n",
+   debugBelch("addSection: %p-%p (size %d), kind %d\n",
                    start, ((char*)end)-1, end - start + 1, kind );
    */
 }
 
 
+/* --------------------------------------------------------------------------
+ * PowerPC specifics (jump islands)
+ * ------------------------------------------------------------------------*/
+
+#if defined(powerpc_TARGET_ARCH)
+
+/*
+  ocAllocateJumpIslands
+  
+  Allocate additional space at the end of the object file image to make room
+  for jump islands.
+  
+  PowerPC relative branch instructions have a 24 bit displacement field.
+  As PPC code is always 4-byte-aligned, this yields a +-32MB range.
+  If a particular imported symbol is outside this range, we have to redirect
+  the jump to a short piece of new code that just loads the 32bit absolute
+  address and jumps there.
+  This function just allocates space for one 16 byte ppcJumpIsland for every
+  undefined symbol in the object file. The code for the islands is filled in by
+  makeJumpIsland below.
+*/
+
+static int ocAllocateJumpIslands( ObjectCode* oc, int count, int first )
+{
+  int aligned;
+
+  if( count > 0 )
+  {
+#ifdef USE_MMAP
+    #error ocAllocateJumpIslands doesnt want USE_MMAP to be defined
+#endif
+    // round up to the nearest 4
+    aligned = (oc->fileSize + 3) & ~3;
+
+    oc->image = stgReallocBytes( oc->image,
+                                 aligned + sizeof( ppcJumpIsland ) * count,
+                                 "ocAllocateJumpIslands" );
+    oc->jump_islands = (ppcJumpIsland *) (((char *) oc->image) + aligned);
+    memset( oc->jump_islands, 0, sizeof( ppcJumpIsland ) * count );
+  }
+  else
+    oc->jump_islands = NULL;
+
+  oc->island_start_symbol = first;
+  oc->n_islands = count;
+
+  return 1;
+}
+
+static unsigned long makeJumpIsland( ObjectCode* oc,
+                                     unsigned long symbolNumber,
+                                     unsigned long target )
+{
+  ppcJumpIsland *island;
+
+  if( symbolNumber < oc->island_start_symbol ||
+      symbolNumber - oc->island_start_symbol > oc->n_islands)
+    return 0;
+
+  island = &oc->jump_islands[symbolNumber - oc->island_start_symbol];
+
+  // lis r12, hi16(target)
+  island->lis_r12     = 0x3d80;
+  island->hi_addr     = target >> 16;
+
+  // ori r12, r12, lo16(target)
+  island->ori_r12_r12 = 0x618c;
+  island->lo_addr     = target & 0xffff;
+
+  // mtctr r12
+  island->mtctr_r12   = 0x7d8903a6;
+
+  // bctr
+  island->bctr        = 0x4e800420;
+    
+  return (unsigned long) island;
+}
+
+/*
+   ocFlushInstructionCache
+
+   Flush the data & instruction caches.
+   Because the PPC has split data/instruction caches, we have to
+   do that whenever we modify code at runtime.
+ */
+
+static void ocFlushInstructionCache( ObjectCode *oc )
+{
+    int n = (oc->fileSize + sizeof( ppcJumpIsland ) * oc->n_islands + 3) / 4;
+    unsigned long *p = (unsigned long *) oc->image;
+
+    while( n-- )
+    {
+        __asm__ volatile ( "dcbf 0,%0\n\t"
+                           "sync\n\t"
+                           "icbi 0,%0"
+                           :
+                           : "r" (p)
+                         );
+        p++;
+    }
+    __asm__ volatile ( "sync\n\t"
+                       "isync"
+                     );
+}
+#endif
 
 /* --------------------------------------------------------------------------
  * PEi386 specifics (Win32 targets)
@@ -1318,12 +1541,12 @@ printName ( UChar* name, UChar* strtab )
 {
    if (name[0]==0 && name[1]==0 && name[2]==0 && name[3]==0) {
       UInt32 strtab_offset = * (UInt32*)(name+4);
-      fprintf ( stderr, "%s", strtab + strtab_offset );
+      debugBelch("%s", strtab + strtab_offset );
    } else {
       int i;
       for (i = 0; i < 8; i++) {
          if (name[i] == 0) break;
-         fprintf ( stderr, "%c", name[i] );
+         debugBelch("%c", name[i] );
       }
    }
 }
@@ -1430,7 +1653,7 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
    COFF_section* sectab;
    COFF_symbol*  symtab;
    UChar*        strtab;
-   /* fprintf(stderr, "\nLOADING %s\n", oc->fileName); */
+   /* debugBelch("\nLOADING %s\n", oc->fileName); */
    hdr = (COFF_header*)(oc->image);
    sectab = (COFF_section*) (
                ((UChar*)(oc->image))
@@ -1444,36 +1667,36 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
             + hdr->NumberOfSymbols * sizeof_COFF_symbol;
 
    if (hdr->Machine != 0x14c) {
-      belch("Not x86 PEi386");
+      errorBelch("Not x86 PEi386");
       return 0;
    }
    if (hdr->SizeOfOptionalHeader != 0) {
-      belch("PEi386 with nonempty optional header");
+      errorBelch("PEi386 with nonempty optional header");
       return 0;
    }
    if ( /* (hdr->Characteristics & MYIMAGE_FILE_RELOCS_STRIPPED) || */
         (hdr->Characteristics & MYIMAGE_FILE_EXECUTABLE_IMAGE) ||
         (hdr->Characteristics & MYIMAGE_FILE_DLL) ||
         (hdr->Characteristics & MYIMAGE_FILE_SYSTEM) ) {
-      belch("Not a PEi386 object file");
+      errorBelch("Not a PEi386 object file");
       return 0;
    }
    if ( (hdr->Characteristics & MYIMAGE_FILE_BYTES_REVERSED_HI)
         /* || !(hdr->Characteristics & MYIMAGE_FILE_32BIT_MACHINE) */ ) {
-      belch("Invalid PEi386 word size or endiannness: %d",
+      errorBelch("Invalid PEi386 word size or endiannness: %d",
             (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); */
+   /* debugBelch("strtab size %d\n", * (UInt32*)strtab); */
 #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?");
+      debugBelch("PEi386 object has suspiciously large string table; > 64k relocs?");
       return 0;
    }
 #endif
@@ -1483,44 +1706,34 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
    IF_DEBUG(linker, i=1);
    if (i == 0) return 1;
 
-   fprintf ( stderr,
-             "sectab offset = %d\n", ((UChar*)sectab) - ((UChar*)hdr) );
-   fprintf ( stderr,
-             "symtab offset = %d\n", ((UChar*)symtab) - ((UChar*)hdr) );
-   fprintf ( stderr,
-             "strtab offset = %d\n", ((UChar*)strtab) - ((UChar*)hdr) );
-
-   fprintf ( stderr, "\n" );
-   fprintf ( stderr,
-             "Machine:           0x%x\n", (UInt32)(hdr->Machine) );
-   fprintf ( stderr,
-             "# sections:        %d\n",   (UInt32)(hdr->NumberOfSections) );
-   fprintf ( stderr,
-             "time/date:         0x%x\n", (UInt32)(hdr->TimeDateStamp) );
-   fprintf ( stderr,
-             "symtab offset:     %d\n",   (UInt32)(hdr->PointerToSymbolTable) );
-   fprintf ( stderr,
-             "# symbols:         %d\n",   (UInt32)(hdr->NumberOfSymbols) );
-   fprintf ( stderr,
-             "sz of opt hdr:     %d\n",   (UInt32)(hdr->SizeOfOptionalHeader) );
-   fprintf ( stderr,
-             "characteristics:   0x%x\n", (UInt32)(hdr->Characteristics) );
+   debugBelch( "sectab offset = %d\n", ((UChar*)sectab) - ((UChar*)hdr) );
+   debugBelch( "symtab offset = %d\n", ((UChar*)symtab) - ((UChar*)hdr) );
+   debugBelch( "strtab offset = %d\n", ((UChar*)strtab) - ((UChar*)hdr) );
+
+   debugBelch("\n" );
+   debugBelch( "Machine:           0x%x\n", (UInt32)(hdr->Machine) );
+   debugBelch( "# sections:        %d\n",   (UInt32)(hdr->NumberOfSections) );
+   debugBelch( "time/date:         0x%x\n", (UInt32)(hdr->TimeDateStamp) );
+   debugBelch( "symtab offset:     %d\n",   (UInt32)(hdr->PointerToSymbolTable) );
+   debugBelch( "# symbols:         %d\n",   (UInt32)(hdr->NumberOfSymbols) );
+   debugBelch( "sz of opt hdr:     %d\n",   (UInt32)(hdr->SizeOfOptionalHeader) );
+   debugBelch( "characteristics:   0x%x\n", (UInt32)(hdr->Characteristics) );
 
    /* Print the section table. */
-   fprintf ( stderr, "\n" );
+   debugBelch("\n" );
    for (i = 0; i < hdr->NumberOfSections; i++) {
       COFF_reloc* reltab;
       COFF_section* sectab_i
          = (COFF_section*)
            myindex ( sizeof_COFF_section, sectab, i );
-      fprintf ( stderr,
+      debugBelch(
                 "\n"
                 "section %d\n"
                 "     name `",
                 i
               );
       printName ( sectab_i->Name, strtab );
-      fprintf ( stderr,
+      debugBelch(
                 "'\n"
                 "    vsize %d\n"
                 "    vaddr %d\n"
@@ -1560,7 +1773,7 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
          COFF_symbol* sym;
          COFF_reloc* rel = (COFF_reloc*)
                            myindex ( sizeof_COFF_reloc, reltab, j );
-         fprintf ( stderr,
+         debugBelch(
                    "        type 0x%-4x   vaddr 0x%-8x   name `",
                    (UInt32)rel->Type,
                    rel->VirtualAddress );
@@ -1568,35 +1781,35 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
                myindex ( sizeof_COFF_symbol, symtab, rel->SymbolTableIndex );
         /* Hmm..mysterious looking offset - what's it for? SOF */
          printName ( sym->Name, strtab -10 );
-         fprintf ( stderr, "'\n" );
+         debugBelch("'\n" );
       }
 
-      fprintf ( stderr, "\n" );
+      debugBelch("\n" );
    }
-   fprintf ( stderr, "\n" );
-   fprintf ( stderr, "string table has size 0x%x\n", * (UInt32*)strtab );
-   fprintf ( stderr, "---START of string table---\n");
+   debugBelch("\n" );
+   debugBelch("string table has size 0x%x\n", * (UInt32*)strtab );
+   debugBelch("---START of string table---\n");
    for (i = 4; i < *(Int32*)strtab; i++) {
       if (strtab[i] == 0)
-         fprintf ( stderr, "\n"); else
-         fprintf( stderr, "%c", strtab[i] );
+         debugBelch("\n"); else
+         debugBelch("%c", strtab[i] );
    }
-   fprintf ( stderr, "--- END  of string table---\n");
+   debugBelch("--- END  of string table---\n");
 
-   fprintf ( stderr, "\n" );
+   debugBelch("\n" );
    i = 0;
    while (1) {
       COFF_symbol* symtab_i;
       if (i >= (Int32)(hdr->NumberOfSymbols)) break;
       symtab_i = (COFF_symbol*)
                  myindex ( sizeof_COFF_symbol, symtab, i );
-      fprintf ( stderr,
+      debugBelch(
                 "symbol %d\n"
                 "     name `",
                 i
               );
       printName ( symtab_i->Name, strtab );
-      fprintf ( stderr,
+      debugBelch(
                 "'\n"
                 "    value 0x%x\n"
                 "   1+sec# %d\n"
@@ -1613,7 +1826,7 @@ ocVerifyImage_PEi386 ( ObjectCode* oc )
       i++;
    }
 
-   fprintf ( stderr, "\n" );
+   debugBelch("\n" );
    return 1;
 }
 
@@ -1659,7 +1872,7 @@ ocGetNames_PEi386 ( ObjectCode* oc )
                               "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); */
+      /* debugBelch("BSS anon section at 0x%x\n", zspace); */
    }
 
    /* Copy section information into the ObjectCode. */
@@ -1674,7 +1887,7 @@ ocGetNames_PEi386 ( ObjectCode* oc )
       COFF_section* sectab_i
          = (COFF_section*)
            myindex ( sizeof_COFF_section, sectab, i );
-      IF_DEBUG(linker, belch("section name = %s\n", sectab_i->Name ));
+      IF_DEBUG(linker, debugBelch("section name = %s\n", sectab_i->Name ));
 
 #     if 0
       /* I'm sure this is the Right Way to do it.  However, the
@@ -1706,7 +1919,7 @@ ocGetNames_PEi386 ( ObjectCode* oc )
           && 0 != strcmp(".stab", sectab_i->Name)
           && 0 != strcmp(".stabstr", sectab_i->Name)
          ) {
-         belch("Unknown PEi386 section name `%s'", sectab_i->Name);
+         errorBelch("Unknown PEi386 section name `%s'", sectab_i->Name);
          return 0;
       }
 
@@ -1760,26 +1973,26 @@ ocGetNames_PEi386 ( ObjectCode* oc )
          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); */
+         /* debugBelch("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);)
+         /* debugBelch("addSymbol %p `%s \n", addr,sname);  */
+         IF_DEBUG(linker, debugBelch("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,
+         debugBelch(
                    "IGNORING symbol %d\n"
                    "     name `",
                    i
                  );
          printName ( symtab_i->Name, strtab );
-         fprintf ( stderr,
+         debugBelch(
                    "'\n"
                    "    value 0x%x\n"
                    "   1+sec# %d\n"
@@ -1821,7 +2034,7 @@ ocResolve_PEi386 ( ObjectCode* oc )
    /* ToDo: should be variable-sized?  But is at least safe in the
       sense of buffer-overrun-proof. */
    char symbol[1000];
-   /* fprintf(stderr, "resolving for %s\n", oc->fileName); */
+   /* debugBelch("resolving for %s\n", oc->fileName); */
 
    hdr = (COFF_header*)(oc->image);
    sectab = (COFF_section*) (
@@ -1856,11 +2069,17 @@ ocResolve_PEi386 ( ObjectCode* oc )
         * real count can be found in the first reloc entry.
          *
         * See Section 4.1 (last para) of the PE spec (rev6.0).
+        *
+        * Nov2003 update: the GNU linker still doesn't correctly
+        * handle the generation of relocatable object files with
+        * overflown relocations. Hence the output to warn of potential
+        * troubles.
         */
         COFF_reloc* rel = (COFF_reloc*)
                            myindex ( sizeof_COFF_reloc, reltab, 0 );
        noRelocs = rel->VirtualAddress;
-       fprintf(stderr, "Overflown relocs: %u\n", noRelocs);
+       debugBelch("WARNING: Overflown relocation field (# relocs found: %u)\n",
+                  noRelocs);
        j = 1;
       } else {
        noRelocs = sectab_i->NumberOfRelocations;
@@ -1888,20 +2107,20 @@ ocResolve_PEi386 ( ObjectCode* oc )
                myindex ( sizeof_COFF_symbol,
                          symtab, reltab_j->SymbolTableIndex );
          IF_DEBUG(linker,
-                  fprintf ( stderr,
+                  debugBelch(
                             "reloc sec %2d num %3d:  type 0x%-4x   "
                             "vaddr 0x%-8x   name `",
                             i, j,
                             (UInt32)reltab_j->Type,
                             reltab_j->VirtualAddress );
                             printName ( sym->Name, strtab );
-                            fprintf ( stderr, "'\n" ));
+                            debugBelch("'\n" ));
 
          if (sym->StorageClass == MYIMAGE_SYM_CLASS_STATIC) {
             COFF_section* section_sym
                = findPEi386SectionCalled ( oc, sym->Name );
             if (!section_sym) {
-               belch("%s: can't find section `%s'", oc->fileName, sym->Name);
+               errorBelch("%s: can't find section `%s'", oc->fileName, sym->Name);
                return 0;
             }
             S = ((UInt32)(oc->image))
@@ -1919,7 +2138,7 @@ ocResolve_PEi386 ( ObjectCode* oc )
             (void*)S = lookupSymbol( symbol );
             if ((void*)S != NULL) goto foundit;
            /* Newline first because the interactive linker has printed "linking..." */
-            belch("\n%s: unknown symbol `%s'", oc->fileName, symbol);
+            errorBelch("\n%s: unknown symbol `%s'", oc->fileName, symbol);
             return 0;
            foundit:
          }
@@ -1944,7 +2163,7 @@ ocResolve_PEi386 ( ObjectCode* oc )
                *pP = S - ((UInt32)pP) - 4;
                break;
             default:
-               belch("%s: unhandled PEi386 relocation type %d",
+               debugBelch("%s: unhandled PEi386 relocation type %d",
                     oc->fileName, reltab_j->Type);
                return 0;
          }
@@ -1952,7 +2171,7 @@ ocResolve_PEi386 ( ObjectCode* oc )
       }
    }
 
-   IF_DEBUG(linker, belch("completed %s", oc->fileName));
+   IF_DEBUG(linker, debugBelch("completed %s", oc->fileName));
    return 1;
 }
 
@@ -1972,6 +2191,9 @@ ocResolve_PEi386 ( ObjectCode* oc )
 #  define ELF_TARGET_SPARC  /* Used inside <elf.h> */
 #elif defined(i386_TARGET_ARCH)
 #  define ELF_TARGET_386    /* Used inside <elf.h> */
+#elif defined(x86_64_TARGET_ARCH)
+#  define ELF_TARGET_X64_64
+#  define ELF_64BIT
 #elif defined (ia64_TARGET_ARCH)
 #  define ELF_TARGET_IA64   /* Used inside <elf.h> */
 #  define ELF_64BIT
@@ -1980,7 +2202,15 @@ ocResolve_PEi386 ( ObjectCode* oc )
 #  define ELF_NEED_PLT      /* needs Procedure Linkage Tables */
 #endif
 
+#if !defined(openbsd_TARGET_OS)
 #include <elf.h>
+#else
+/* openbsd elf has things in different places, with diff names */
+#include <elf_abi.h>
+#include <machine/reloc.h>
+#define R_386_32    RELOC_32
+#define R_386_PC32  RELOC_PC32
+#endif
 
 /*
  * Define a set of types which can be used for both ELF32 and ELF64
@@ -2012,11 +2242,19 @@ ocResolve_PEi386 ( ObjectCode* oc )
 #define Elf_Sym     Elf32_Sym
 #define Elf_Rel     Elf32_Rel
 #define Elf_Rela    Elf32_Rela
+#ifndef ELF_ST_TYPE
 #define ELF_ST_TYPE ELF32_ST_TYPE
+#endif
+#ifndef ELF_ST_BIND
 #define ELF_ST_BIND ELF32_ST_BIND
+#endif
+#ifndef ELF_R_TYPE
 #define ELF_R_TYPE  ELF32_R_TYPE
+#endif
+#ifndef ELF_R_SYM
 #define ELF_R_SYM   ELF32_R_SYM
 #endif
+#endif
 
 
 /*
@@ -2202,44 +2440,45 @@ ocVerifyImage_ELF ( ObjectCode* oc )
        ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
        ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
        ehdr->e_ident[EI_MAG3] != ELFMAG3) {
-      belch("%s: not an ELF object", oc->fileName);
+      errorBelch("%s: not an ELF object", oc->fileName);
       return 0;
    }
 
    if (ehdr->e_ident[EI_CLASS] != ELFCLASS) {
-      belch("%s: unsupported ELF format", oc->fileName);
+      errorBelch("%s: unsupported ELF format", oc->fileName);
       return 0;
    }
 
    if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) {
-       IF_DEBUG(linker,belch( "Is little-endian" ));
+       IF_DEBUG(linker,debugBelch( "Is little-endian" ));
    } else
    if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) {
-       IF_DEBUG(linker,belch( "Is big-endian" ));
+       IF_DEBUG(linker,debugBelch( "Is big-endian" ));
    } else {
-       belch("%s: unknown endiannness", oc->fileName);
+       errorBelch("%s: unknown endiannness", oc->fileName);
        return 0;
    }
 
    if (ehdr->e_type != ET_REL) {
-      belch("%s: not a relocatable object (.o) file", oc->fileName);
+      errorBelch("%s: not a relocatable object (.o) file", oc->fileName);
       return 0;
    }
-   IF_DEBUG(linker, belch( "Is a relocatable object (.o) file" ));
+   IF_DEBUG(linker, debugBelch( "Is a relocatable object (.o) file" ));
 
-   IF_DEBUG(linker,belch( "Architecture is " ));
+   IF_DEBUG(linker,debugBelch( "Architecture is " ));
    switch (ehdr->e_machine) {
-      case EM_386:   IF_DEBUG(linker,belch( "x86" )); break;
-      case EM_SPARC: IF_DEBUG(linker,belch( "sparc" )); break;
+      case EM_386:   IF_DEBUG(linker,debugBelch( "x86" )); break;
+      case EM_SPARC: IF_DEBUG(linker,debugBelch( "sparc" )); break;
 #ifdef EM_IA_64
-      case EM_IA_64: IF_DEBUG(linker,belch( "ia64" )); break;
+      case EM_IA_64: IF_DEBUG(linker,debugBelch( "ia64" )); break;
 #endif
-      default:       IF_DEBUG(linker,belch( "unknown" ));
-                     belch("%s: unknown architecture", oc->fileName);
+      case EM_PPC:   IF_DEBUG(linker,debugBelch( "powerpc32" )); break;
+      default:       IF_DEBUG(linker,debugBelch( "unknown" ));
+                     errorBelch("%s: unknown architecture", oc->fileName);
                      return 0;
    }
 
-   IF_DEBUG(linker,belch(
+   IF_DEBUG(linker,debugBelch(
              "\nSection header table: start %d, n_entries %d, ent_size %d",
              ehdr->e_shoff, ehdr->e_shnum, ehdr->e_shentsize  ));
 
@@ -2248,36 +2487,36 @@ ocVerifyImage_ELF ( ObjectCode* oc )
    shdr = (Elf_Shdr*) (ehdrC + ehdr->e_shoff);
 
    if (ehdr->e_shstrndx == SHN_UNDEF) {
-      belch("%s: no section header string table", oc->fileName);
+      errorBelch("%s: no section header string table", oc->fileName);
       return 0;
    } else {
-      IF_DEBUG(linker,belch( "Section header string table is section %d",
+      IF_DEBUG(linker,debugBelch( "Section header string table is section %d",
                           ehdr->e_shstrndx));
       sh_strtab = ehdrC + shdr[ehdr->e_shstrndx].sh_offset;
    }
 
    for (i = 0; i < ehdr->e_shnum; i++) {
-      IF_DEBUG(linker,fprintf(stderr, "%2d:  ", i ));
-      IF_DEBUG(linker,fprintf(stderr, "type=%2d  ", (int)shdr[i].sh_type ));
-      IF_DEBUG(linker,fprintf(stderr, "size=%4d  ", (int)shdr[i].sh_size ));
-      IF_DEBUG(linker,fprintf(stderr, "offs=%4d  ", (int)shdr[i].sh_offset ));
-      IF_DEBUG(linker,fprintf(stderr, "  (%p .. %p)  ",
+      IF_DEBUG(linker,debugBelch("%2d:  ", i ));
+      IF_DEBUG(linker,debugBelch("type=%2d  ", (int)shdr[i].sh_type ));
+      IF_DEBUG(linker,debugBelch("size=%4d  ", (int)shdr[i].sh_size ));
+      IF_DEBUG(linker,debugBelch("offs=%4d  ", (int)shdr[i].sh_offset ));
+      IF_DEBUG(linker,debugBelch("  (%p .. %p)  ",
                ehdrC + shdr[i].sh_offset,
                      ehdrC + shdr[i].sh_offset + shdr[i].sh_size - 1));
 
       if (shdr[i].sh_type == SHT_REL) {
-         IF_DEBUG(linker,fprintf(stderr, "Rel  " ));
+         IF_DEBUG(linker,debugBelch("Rel  " ));
       } else if (shdr[i].sh_type == SHT_RELA) {
-         IF_DEBUG(linker,fprintf(stderr, "RelA " ));
+         IF_DEBUG(linker,debugBelch("RelA " ));
       } else {
-         IF_DEBUG(linker,fprintf(stderr,"     "));
+         IF_DEBUG(linker,debugBelch("     "));
       }
       if (sh_strtab) {
-         IF_DEBUG(linker,fprintf(stderr, "sname=%s\n", sh_strtab + shdr[i].sh_name ));
+         IF_DEBUG(linker,debugBelch("sname=%s\n", sh_strtab + shdr[i].sh_name ));
       }
    }
 
-   IF_DEBUG(linker,belch( "\nString tables" ));
+   IF_DEBUG(linker,debugBelch( "\nString tables" ));
    strtab = NULL;
    nstrtab = 0;
    for (i = 0; i < ehdr->e_shnum; i++) {
@@ -2288,65 +2527,65 @@ ocVerifyImage_ELF ( ObjectCode* oc )
              debugging info. */
           && 0 != memcmp(".stabstr", sh_strtab + shdr[i].sh_name, 8)
          ) {
-         IF_DEBUG(linker,belch("   section %d is a normal string table", i ));
+         IF_DEBUG(linker,debugBelch("   section %d is a normal string table", i ));
          strtab = ehdrC + shdr[i].sh_offset;
          nstrtab++;
       }
    }
    if (nstrtab != 1) {
-      belch("%s: no string tables, or too many", oc->fileName);
+      errorBelch("%s: no string tables, or too many", oc->fileName);
       return 0;
    }
 
    nsymtabs = 0;
-   IF_DEBUG(linker,belch( "\nSymbol tables" ));
+   IF_DEBUG(linker,debugBelch( "\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 ));
+      IF_DEBUG(linker,debugBelch( "section %d is a symbol table", i ));
       nsymtabs++;
       stab = (Elf_Sym*) (ehdrC + shdr[i].sh_offset);
       nent = shdr[i].sh_size / sizeof(Elf_Sym);
-      IF_DEBUG(linker,belch( "   number of entries is apparently %d (%d rem)",
+      IF_DEBUG(linker,debugBelch( "   number of entries is apparently %d (%d rem)",
                nent,
                shdr[i].sh_size % sizeof(Elf_Sym)
              ));
       if (0 != shdr[i].sh_size % sizeof(Elf_Sym)) {
-         belch("%s: non-integral number of symbol table entries", oc->fileName);
+         errorBelch("%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 ));
-         IF_DEBUG(linker,fprintf(stderr, "  sec=%-5d  size=%-3d  val=%5p  ",
+         IF_DEBUG(linker,debugBelch("   %2d  ", j ));
+         IF_DEBUG(linker,debugBelch("  sec=%-5d  size=%-3d  val=%5p  ",
                              (int)stab[j].st_shndx,
                              (int)stab[j].st_size,
                              (char*)stab[j].st_value ));
 
-         IF_DEBUG(linker,fprintf(stderr, "type=" ));
+         IF_DEBUG(linker,debugBelch("type=" ));
          switch (ELF_ST_TYPE(stab[j].st_info)) {
-            case STT_NOTYPE:  IF_DEBUG(linker,fprintf(stderr, "notype " )); break;
-            case STT_OBJECT:  IF_DEBUG(linker,fprintf(stderr, "object " )); break;
-            case STT_FUNC  :  IF_DEBUG(linker,fprintf(stderr, "func   " )); break;
-            case STT_SECTION: IF_DEBUG(linker,fprintf(stderr, "section" )); break;
-            case STT_FILE:    IF_DEBUG(linker,fprintf(stderr, "file   " )); break;
-            default:          IF_DEBUG(linker,fprintf(stderr, "?      " )); break;
+            case STT_NOTYPE:  IF_DEBUG(linker,debugBelch("notype " )); break;
+            case STT_OBJECT:  IF_DEBUG(linker,debugBelch("object " )); break;
+            case STT_FUNC  :  IF_DEBUG(linker,debugBelch("func   " )); break;
+            case STT_SECTION: IF_DEBUG(linker,debugBelch("section" )); break;
+            case STT_FILE:    IF_DEBUG(linker,debugBelch("file   " )); break;
+            default:          IF_DEBUG(linker,debugBelch("?      " )); break;
          }
-         IF_DEBUG(linker,fprintf(stderr, "  " ));
+         IF_DEBUG(linker,debugBelch("  " ));
 
-         IF_DEBUG(linker,fprintf(stderr, "bind=" ));
+         IF_DEBUG(linker,debugBelch("bind=" ));
          switch (ELF_ST_BIND(stab[j].st_info)) {
-            case STB_LOCAL :  IF_DEBUG(linker,fprintf(stderr, "local " )); break;
-            case STB_GLOBAL:  IF_DEBUG(linker,fprintf(stderr, "global" )); break;
-            case STB_WEAK  :  IF_DEBUG(linker,fprintf(stderr, "weak  " )); break;
-            default:          IF_DEBUG(linker,fprintf(stderr, "?     " )); break;
+            case STB_LOCAL :  IF_DEBUG(linker,debugBelch("local " )); break;
+            case STB_GLOBAL:  IF_DEBUG(linker,debugBelch("global" )); break;
+            case STB_WEAK  :  IF_DEBUG(linker,debugBelch("weak  " )); break;
+            default:          IF_DEBUG(linker,debugBelch("?     " )); break;
          }
-         IF_DEBUG(linker,fprintf(stderr, "  " ));
+         IF_DEBUG(linker,debugBelch("  " ));
 
-         IF_DEBUG(linker,fprintf(stderr, "name=%s\n", strtab + stab[j].st_name ));
+         IF_DEBUG(linker,debugBelch("name=%s\n", strtab + stab[j].st_name ));
       }
    }
 
    if (nsymtabs == 0) {
-      belch("%s: didn't find any symbol tables", oc->fileName);
+      errorBelch("%s: didn't find any symbol tables", oc->fileName);
       return 0;
    }
 
@@ -2368,7 +2607,7 @@ ocGetNames_ELF ( ObjectCode* oc )
    ASSERT(symhash != NULL);
 
    if (!strtab) {
-      belch("%s: no strtab", oc->fileName);
+      errorBelch("%s: no strtab", oc->fileName);
       return 0;
    }
 
@@ -2414,7 +2653,7 @@ ocGetNames_ELF ( ObjectCode* oc )
                                        "ocGetNames_ELF(BSS)");
          shdr[i].sh_offset = ((char*)zspace) - ((char*)ehdrC);
         /*
-         fprintf(stderr, "BSS section at 0x%x, size %d\n",
+         debugBelch("BSS section at 0x%x, size %d\n",
                          zspace, shdr[i].sh_size);
         */
       }
@@ -2450,7 +2689,7 @@ ocGetNames_ELF ( ObjectCode* oc )
             isLocal = FALSE;
             ad = stgCallocBytes(1, stab[j].st_size, "ocGetNames_ELF(COMMON)");
            /*
-            fprintf(stderr, "COMMON symbol, size %d name %s\n",
+            debugBelch("COMMON symbol, size %d name %s\n",
                             stab[j].st_size, nm);
            */
            /* Pointless to do addProddableBlock() for this area,
@@ -2475,7 +2714,7 @@ ocGetNames_ELF ( ObjectCode* oc )
             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",
+               debugBelch("   BSS symbol, size %d off %d name %s\n",
                                stab[j].st_size, stab[j].st_value, nm);
             }
             */
@@ -2490,7 +2729,7 @@ ocGetNames_ELF ( ObjectCode* oc )
                if (ELF_ST_TYPE(stab[j].st_info) == STT_FUNC)
                    ad = (char *)allocateFunctionDesc((Elf_Addr)ad);
 #endif
-               IF_DEBUG(linker,belch( "addOTabName(GLOB): %10p  %s %s",
+               IF_DEBUG(linker,debugBelch( "addOTabName(GLOB): %10p  %s %s",
                                       ad, oc->fileName, nm ));
                isLocal = FALSE;
             }
@@ -2509,10 +2748,10 @@ ocGetNames_ELF ( ObjectCode* oc )
             }
          } else {
             /* Skip. */
-            IF_DEBUG(linker,belch( "skipping `%s'",
+            IF_DEBUG(linker,debugBelch( "skipping `%s'",
                                    strtab + stab[j].st_name ));
             /*
-            fprintf(stderr,
+            debugBelch(
                     "skipping   bind = %d,  type = %d,  shndx = %d   `%s'\n",
                     (int)ELF_ST_BIND(stab[j].st_info),
                     (int)ELF_ST_TYPE(stab[j].st_info),
@@ -2546,7 +2785,7 @@ do_Elf_Rel_relocations ( ObjectCode* oc, char* ehdrC,
 
    stab  = (Elf_Sym*) (ehdrC + shdr[ symtab_shndx ].sh_offset);
    targ  = (Elf_Word*)(ehdrC + shdr[ target_shndx ].sh_offset);
-   IF_DEBUG(linker,belch( "relocations for section %d using symtab %d",
+   IF_DEBUG(linker,debugBelch( "relocations for section %d using symtab %d",
                           target_shndx, symtab_shndx ));
 
    for (j = 0; j < nent; j++) {
@@ -2557,12 +2796,13 @@ do_Elf_Rel_relocations ( ObjectCode* oc, char* ehdrC,
       Elf_Word* pP = (Elf_Word*)P;
       Elf_Addr  A  = *pP;
       Elf_Addr  S;
+      void*     S_tmp;
       Elf_Addr  value;
 
-      IF_DEBUG(linker,belch( "Rel entry %3d is raw(%6p %6p)",
+      IF_DEBUG(linker,debugBelch( "Rel entry %3d is raw(%6p %6p)",
                              j, (void*)offset, (void*)info ));
       if (!info) {
-         IF_DEBUG(linker,belch( " ZERO" ));
+         IF_DEBUG(linker,debugBelch( " ZERO" ));
          S = 0;
       } else {
          Elf_Sym sym = stab[ELF_R_SYM(info)];
@@ -2578,16 +2818,17 @@ do_Elf_Rel_relocations ( ObjectCode* oc, char* ehdrC,
         } else {
             /* No, so look up the name in our global table. */
             symbol = strtab + sym.st_name;
-            (void*)S = lookupSymbol( symbol );
+            S_tmp = lookupSymbol( symbol );
+            S = (Elf_Addr)S_tmp;
         }
          if (!S) {
-            belch("%s: unknown symbol `%s'", oc->fileName, symbol);
+            errorBelch("%s: unknown symbol `%s'", oc->fileName, symbol);
            return 0;
          }
-         IF_DEBUG(linker,belch( "`%s' resolves to %p", symbol, (void*)S ));
+         IF_DEBUG(linker,debugBelch( "`%s' resolves to %p", symbol, (void*)S ));
       }
 
-      IF_DEBUG(linker,belch( "Reloc: P = %p   S = %p   A = %p",
+      IF_DEBUG(linker,debugBelch( "Reloc: P = %p   S = %p   A = %p",
                             (void*)P, (void*)S, (void*)A ));
       checkProddableBlock ( oc, pP );
 
@@ -2599,7 +2840,7 @@ do_Elf_Rel_relocations ( ObjectCode* oc, char* ehdrC,
          case R_386_PC32: *pP = value - P; break;
 #        endif
          default:
-            belch("%s: unhandled ELF relocation(Rel) type %d\n",
+            errorBelch("%s: unhandled ELF relocation(Rel) type %d\n",
                  oc->fileName, ELF_R_TYPE(info));
             return 0;
       }
@@ -2625,11 +2866,11 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
 
    stab  = (Elf_Sym*) (ehdrC + shdr[ symtab_shndx ].sh_offset);
    targ  = (Elf_Addr) (ehdrC + shdr[ target_shndx ].sh_offset);
-   IF_DEBUG(linker,belch( "relocations for section %d using symtab %d",
+   IF_DEBUG(linker,debugBelch( "relocations for section %d using symtab %d",
                           target_shndx, symtab_shndx ));
 
    for (j = 0; j < nent; j++) {
-#if defined(DEBUG) || defined(sparc_TARGET_ARCH) || defined(ia64_TARGET_ARCH)
+#if defined(DEBUG) || defined(sparc_TARGET_ARCH) || defined(ia64_TARGET_ARCH) || defined(powerpc_TARGET_ARCH)
       /* This #ifdef only serves to avoid unused-var warnings. */
       Elf_Addr  offset = rtab[j].r_offset;
       Elf_Addr  P      = targ + offset;
@@ -2637,6 +2878,7 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
       Elf_Addr  info   = rtab[j].r_info;
       Elf_Addr  A      = rtab[j].r_addend;
       Elf_Addr  S;
+      void*     S_tmp;
       Elf_Addr  value;
 #     if defined(sparc_TARGET_ARCH)
       Elf_Word* pP = (Elf_Word*)P;
@@ -2644,13 +2886,15 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
 #     elif defined(ia64_TARGET_ARCH)
       Elf64_Xword *pP = (Elf64_Xword *)P;
       Elf_Addr addr;
+#     elif defined(powerpc_TARGET_ARCH)
+      Elf_Sword delta;
 #     endif
 
-      IF_DEBUG(linker,belch( "Rel entry %3d is raw(%6p %6p %6p)   ",
+      IF_DEBUG(linker,debugBelch( "Rel entry %3d is raw(%6p %6p %6p)   ",
                              j, (void*)offset, (void*)info,
                                 (void*)A ));
       if (!info) {
-         IF_DEBUG(linker,belch( " ZERO" ));
+         IF_DEBUG(linker,debugBelch( " ZERO" ));
          S = 0;
       } else {
          Elf_Sym sym = stab[ELF_R_SYM(info)];
@@ -2672,23 +2916,24 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
         } else {
             /* No, so look up the name in our global table. */
             symbol = strtab + sym.st_name;
-            (void*)S = lookupSymbol( symbol );
+            S_tmp = lookupSymbol( symbol );
+            S = (Elf_Addr)S_tmp;
 
 #ifdef ELF_FUNCTION_DESC
            /* If a function, already a function descriptor - we would
               have to copy it to add an offset. */
-            if (S && ELF_ST_TYPE(sym.st_info) == STT_FUNC)
-               assert(A == 0);
+            if (S && (ELF_ST_TYPE(sym.st_info) == STT_FUNC) && (A != 0))
+               errorBelch("%s: function %s with addend %p", oc->fileName, symbol, (void *)A);
 #endif
         }
          if (!S) {
-          belch("%s: unknown symbol `%s'", oc->fileName, symbol);
+          errorBelch("%s: unknown symbol `%s'", oc->fileName, symbol);
           return 0;
          }
-         IF_DEBUG(linker,belch( "`%s' resolves to %p", symbol, (void*)S ));
+         IF_DEBUG(linker,debugBelch( "`%s' resolves to %p", symbol, (void*)S ));
       }
 
-      IF_DEBUG(linker,fprintf ( stderr, "Reloc: P = %p   S = %p   A = %p\n",
+      IF_DEBUG(linker,debugBelch("Reloc: P = %p   S = %p   A = %p\n",
                                         (void*)P, (void*)S, (void*)A ));
       /* checkProddableBlock ( oc, (void*)P ); */
 
@@ -2737,6 +2982,9 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
         case R_IA64_FPTR64LSB:
            *pP = value;
            break;
+        case R_IA64_PCREL64LSB:
+           *pP = value - P;
+           break;
         case R_IA64_SEGREL64LSB:
            addr = findElfSegment(ehdrC, value);
            *pP = value - addr;
@@ -2745,6 +2993,7 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
            ia64_reloc_gprel22(P, value);
            break;
         case R_IA64_LTOFF22:
+        case R_IA64_LTOFF22X:
         case R_IA64_LTOFF_FPTR22:
            addr = allocateGOTEntry(value);
            ia64_reloc_gprel22(P, addr);
@@ -2752,9 +3001,53 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
         case R_IA64_PCREL21B:
            ia64_reloc_pcrel21(P, S, oc);
            break;
+        case R_IA64_LDXMOV:
+           /* This goes with R_IA64_LTOFF22X and points to the load to
+            * convert into a move.  We don't implement relaxation. */
+           break;
+#        elif defined(powerpc_TARGET_ARCH)
+         case R_PPC_ADDR16_LO:
+            *(Elf32_Half*) P = value;
+            break;
+
+         case R_PPC_ADDR16_HI:
+            *(Elf32_Half*) P = value >> 16;
+            break;
+         case R_PPC_ADDR16_HA:
+            *(Elf32_Half*) P = (value + 0x8000) >> 16;
+            break;
+
+         case R_PPC_ADDR32:
+            *(Elf32_Word *) P = value;
+            break;
+
+         case R_PPC_REL32:
+            *(Elf32_Word *) P = value - P;
+            break;
+
+         case R_PPC_REL24:
+            delta = value - P;
+
+            if( delta << 6 >> 6 != delta )
+            {
+               value = makeJumpIsland( oc, ELF_R_SYM(info), value );
+               delta = value - P;
+
+               if( value == 0 || delta << 6 >> 6 != delta )
+               {
+                  barf( "Unable to make ppcJumpIsland for #%d",
+                        ELF_R_SYM(info) );
+                  return 0;
+               }
+            }
+
+            *(Elf_Word *) P = (*(Elf_Word *) P & 0xfc000003)
+                                          | (delta & 0x3fffffc);
+            break;
 #        endif
          default:
-            belch("%s: unhandled ELF relocation(RelA) type %d\n",
+            errorBelch("%s: unhandled ELF relocation(RelA) type %d\n",
                  oc->fileName, ELF_R_TYPE(info));
             return 0;
       }
@@ -2781,7 +3074,7 @@ ocResolve_ELF ( ObjectCode* oc )
    strtab = findElfSection ( ehdrC, SHT_STRTAB );
 
    if (stab == NULL || strtab == NULL) {
-      belch("%s: can't find string or symbol table", oc->fileName);
+      errorBelch("%s: can't find string or symbol table", oc->fileName);
       return 0;
    }
 
@@ -2812,6 +3105,10 @@ ocResolve_ELF ( ObjectCode* oc )
    freeHashTable(oc->lochash, NULL);
    oc->lochash = NULL;
 
+#if defined(powerpc_TARGET_ARCH)
+   ocFlushInstructionCache( oc );
+#endif
+
    return 1;
 }
 
@@ -2907,6 +3204,44 @@ ia64_reloc_pcrel21(Elf_Addr target, Elf_Addr value, ObjectCode *oc)
 
 #endif /* ia64 */
 
+/*
+ * PowerPC ELF specifics
+ */
+
+#ifdef powerpc_TARGET_ARCH
+
+static int ocAllocateJumpIslands_ELF( ObjectCode *oc )
+{
+  Elf_Ehdr *ehdr;
+  Elf_Shdr* shdr;
+  int i;
+
+  ehdr = (Elf_Ehdr *) oc->image;
+  shdr = (Elf_Shdr *) ( ((char *)oc->image) + ehdr->e_shoff );
+
+  for( i = 0; i < ehdr->e_shnum; i++ )
+    if( shdr[i].sh_type == SHT_SYMTAB )
+      break;
+
+  if( i == ehdr->e_shnum )
+  {
+    errorBelch( "This ELF file contains no symtab" );
+    return 0;
+  }
+
+  if( shdr[i].sh_entsize != sizeof( Elf_Sym ) )
+  {
+    errorBelch( "The entry size (%d) of the symtab isn't %d\n",
+      shdr[i].sh_entsize, sizeof( Elf_Sym ) );
+    
+    return 0;
+  }
+
+  return ocAllocateJumpIslands( oc, shdr[i].sh_size / sizeof( Elf_Sym ), 0 );
+}
+
+#endif /* powerpc */
+
 #endif /* ELF */
 
 /* --------------------------------------------------------------------------
@@ -2916,25 +3251,45 @@ ia64_reloc_pcrel21(Elf_Addr target, Elf_Addr value, ObjectCode *oc)
 #if defined(OBJFORMAT_MACHO)
 
 /*
-  Initial support for MachO linking on Darwin/MacOS X on PowerPC chips
+  Support for MachO linking on Darwin/MacOS X on PowerPC chips
   by Wolfgang Thaller (wolfgang.thaller@gmx.net)
-  
+
   I hereby formally apologize for the hackish nature of this code.
   Things that need to be done:
-  *) get common symbols and .bss sections to work properly.
-       Haskell modules seem to work, but C modules can cause problems
   *) implement ocVerifyImage_MachO
-  *) add more sanity checks. The current code just has to segfault if there's a
-     broken .o file.
+  *) add still more sanity checks.
 */
 
+static int ocAllocateJumpIslands_MachO(ObjectCode* oc)
+{
+    struct mach_header *header = (struct mach_header *) oc->image;
+    struct load_command *lc = (struct load_command *) (header + 1);
+    unsigned i;
+
+    for( i = 0; i < header->ncmds; i++ )
+    {
+        if( lc->cmd == LC_DYSYMTAB )
+        {
+            struct dysymtab_command *dsymLC = (struct dysymtab_command *) lc;
+
+            if( !ocAllocateJumpIslands( oc, dsymLC->nundefsym,
+                                            dsymLC->iundefsym ) )
+              return 0;
+
+            break;  // there can be only one LC_DSYMTAB
+        }
+        lc = (struct load_command *) ( ((char *)lc) + lc->cmdsize );
+    }
+    return 1;
+}
+
 static int ocVerifyImage_MachO(ObjectCode* oc)
 {
     // FIXME: do some verifying here
     return 1;
 }
 
-static void resolveImports(
+static int resolveImports(
     ObjectCode* oc,
     char *image,
     struct symtab_command *symLC,
@@ -2943,14 +3298,14 @@ static void resolveImports(
     struct nlist *nlist)
 {
     unsigned i;
-    
+
     for(i=0;i*4<sect->size;i++)
     {
        // according to otool, reserved1 contains the first index into the indirect symbol table
        struct nlist *symbol = &nlist[indirectSyms[sect->reserved1+i]];
        char *nm = image + symLC->stroff + symbol->n_un.n_strx;
        void *addr = NULL;
-       
+
        if((symbol->n_type & N_TYPE) == N_UNDF
            && (symbol->n_type & N_EXT) && (symbol->n_value != 0))
            addr = (void*) (symbol->n_value);
@@ -2960,46 +3315,158 @@ static void resolveImports(
            addr = lookupSymbol(nm);
        if(!addr)
        {
-           fprintf(stderr, "not found: %s\n", nm);
-           abort();
+           errorBelch("\n%s: unknown symbol `%s'", oc->fileName, nm);
+           return 0;
        }
        ASSERT(addr);
+       checkProddableBlock(oc,((void**)(image + sect->offset)) + i);
        ((void**)(image + sect->offset))[i] = addr;
     }
+
+    return 1;
 }
 
-static void relocateSection(char *image, 
+static char* relocateAddress(
+    ObjectCode* oc,
+    int nSections,
+    struct section* sections,
+    unsigned long address)
+{
+    int i;
+    for(i = 0; i < nSections; i++)
+    {
+        if(sections[i].addr <= address
+            && address < sections[i].addr + sections[i].size)
+        {
+            return oc->image + sections[i].offset + address - sections[i].addr;
+        }
+    }
+    barf("Invalid Mach-O file:"
+         "Address out of bounds while relocating object file");
+    return NULL;
+}
+
+static int relocateSection(
+    ObjectCode* oc,
+    char *image,
     struct symtab_command *symLC, struct nlist *nlist,
-    struct section* sections, struct section *sect)
+    int nSections, struct section* sections, struct section *sect)
 {
     struct relocation_info *relocs;
     int i,n;
-    
+
     if(!strcmp(sect->sectname,"__la_symbol_ptr"))
-       return;
+       return 1;
     else if(!strcmp(sect->sectname,"__nl_symbol_ptr"))
-       return;
+       return 1;
 
     n = sect->nreloc;
     relocs = (struct relocation_info*) (image + sect->reloff);
-    
+
     for(i=0;i<n;i++)
     {
        if(relocs[i].r_address & R_SCATTERED)
        {
            struct scattered_relocation_info *scat =
                (struct scattered_relocation_info*) &relocs[i];
-           
+
            if(!scat->r_pcrel)
            {
-               if(scat->r_length == 2 && scat->r_type == GENERIC_RELOC_VANILLA)
+               if(scat->r_length == 2)
                {
-                   unsigned long* word = (unsigned long*) (image + sect->offset + scat->r_address);
-                   
-                   *word = scat->r_value + sect->offset + ((long) image);
+                   unsigned long word = 0;
+                   unsigned long* wordPtr = (unsigned long*) (image + sect->offset + scat->r_address);
+                   checkProddableBlock(oc,wordPtr);
+
+                   // Step 1: Figure out what the relocated value should be
+                   if(scat->r_type == GENERIC_RELOC_VANILLA)
+                   {
+                        word = *wordPtr + (unsigned long) relocateAddress(
+                                                                oc,
+                                                                nSections,
+                                                                sections,
+                                                                scat->r_value)
+                                        - scat->r_value;
+                   }
+                   else if(scat->r_type == PPC_RELOC_SECTDIFF
+                       || scat->r_type == PPC_RELOC_LO16_SECTDIFF
+                       || scat->r_type == PPC_RELOC_HI16_SECTDIFF
+                       || scat->r_type == PPC_RELOC_HA16_SECTDIFF)
+                   {
+                       struct scattered_relocation_info *pair =
+                               (struct scattered_relocation_info*) &relocs[i+1];
+
+                       if(!pair->r_scattered || pair->r_type != PPC_RELOC_PAIR)
+                           barf("Invalid Mach-O file: "
+                                "PPC_RELOC_*_SECTDIFF not followed by PPC_RELOC_PAIR");
+
+                       word = (unsigned long)
+                              (relocateAddress(oc, nSections, sections, scat->r_value)
+                             - relocateAddress(oc, nSections, sections, pair->r_value));
+                       i++;
+                   }
+                   else if(scat->r_type == PPC_RELOC_HI16
+                         || scat->r_type == PPC_RELOC_LO16
+                         || scat->r_type == PPC_RELOC_HA16
+                         || scat->r_type == PPC_RELOC_LO14)
+                    {   // these are generated by label+offset things
+                       struct relocation_info *pair = &relocs[i+1];
+                        if((pair->r_address & R_SCATTERED) || pair->r_type != PPC_RELOC_PAIR)
+                           barf("Invalid Mach-O file: "
+                                "PPC_RELOC_* not followed by PPC_RELOC_PAIR");
+                        
+                        if(scat->r_type == PPC_RELOC_LO16)
+                        {
+                            word = ((unsigned short*) wordPtr)[1];
+                            word |= ((unsigned long) relocs[i+1].r_address & 0xFFFF) << 16;
+                        }
+                        else if(scat->r_type == PPC_RELOC_LO14)
+                        {
+                            barf("Unsupported Relocation: PPC_RELOC_LO14");
+                            word = ((unsigned short*) wordPtr)[1] & 0xFFFC;
+                            word |= ((unsigned long) relocs[i+1].r_address & 0xFFFF) << 16;
+                        }
+                        else if(scat->r_type == PPC_RELOC_HI16)
+                        {
+                            word = ((unsigned short*) wordPtr)[1] << 16;
+                            word |= ((unsigned long) relocs[i+1].r_address & 0xFFFF);
+                        }
+                        else if(scat->r_type == PPC_RELOC_HA16)
+                        {
+                            word = ((unsigned short*) wordPtr)[1] << 16;
+                            word += ((short)relocs[i+1].r_address & (short)0xFFFF);
+                        }
+                       
+                        
+                        word += (unsigned long) relocateAddress(oc, nSections, sections, scat->r_value)
+                                                - scat->r_value;
+                        
+                        i++;
+                    }
+                    else
+                       continue;  // ignore the others
+
+                    if(scat->r_type == GENERIC_RELOC_VANILLA
+                        || scat->r_type == PPC_RELOC_SECTDIFF)
+                    {
+                        *wordPtr = word;
+                    }
+                    else if(scat->r_type == PPC_RELOC_LO16_SECTDIFF || scat->r_type == PPC_RELOC_LO16)
+                    {
+                        ((unsigned short*) wordPtr)[1] = word & 0xFFFF;
+                    }
+                    else if(scat->r_type == PPC_RELOC_HI16_SECTDIFF || scat->r_type == PPC_RELOC_HI16)
+                    {
+                        ((unsigned short*) wordPtr)[1] = (word >> 16) & 0xFFFF;
+                    }
+                    else if(scat->r_type == PPC_RELOC_HA16_SECTDIFF || scat->r_type == PPC_RELOC_HA16)
+                    {
+                        ((unsigned short*) wordPtr)[1] = ((word >> 16) & 0xFFFF)
+                            + ((word & (1<<15)) ? 1 : 0);
+                    }
                }
            }
-           
+
            continue; // FIXME: I hope it's OK to ignore all the others.
        }
        else
@@ -3007,13 +3474,16 @@ static void relocateSection(char *image,
            struct relocation_info *reloc = &relocs[i];
            if(reloc->r_pcrel && !reloc->r_extern)
                continue;
-               
-           if(!reloc->r_pcrel && reloc->r_length == 2)
+
+           if(reloc->r_length == 2)
            {
-               unsigned long word;
+               unsigned long word = 0;
+                unsigned long jumpIsland = 0;
+                long offsetToJumpIsland;
 
                unsigned long* wordPtr = (unsigned long*) (image + sect->offset + reloc->r_address);
-               
+               checkProddableBlock(oc,wordPtr);
+
                if(reloc->r_type == GENERIC_RELOC_VANILLA)
                {
                    word = *wordPtr;
@@ -3033,24 +3503,53 @@ static void relocateSection(char *image,
                    word = ((unsigned short*) wordPtr)[1] << 16;
                    word += ((short)relocs[i+1].r_address & (short)0xFFFF);
                }
+               else if(reloc->r_type == PPC_RELOC_BR24)
+               {
+                   word = *wordPtr;
+                   word = (word & 0x03FFFFFC) | ((word & 0x02000000) ? 0xFC000000 : 0);
+               }
+
 
                if(!reloc->r_extern)
                {
-                   long delta = 
+                   long delta =
                        sections[reloc->r_symbolnum-1].offset
                        - sections[reloc->r_symbolnum-1].addr
                        + ((long) image);
-                   
+
                    word += delta;
                }
                else
                {
                    struct nlist *symbol = &nlist[reloc->r_symbolnum];
                    char *nm = image + symLC->stroff + symbol->n_un.n_strx;
-                   word = (unsigned long) (lookupSymbol(nm));
-                   ASSERT(word);
+                   unsigned long symbolAddress = (unsigned long) (lookupSymbol(nm));
+                   if(!symbolAddress)
+                   {
+                       errorBelch("\nunknown symbol `%s'", nm);
+                       return 0;
+                   }
+
+                   if(reloc->r_pcrel)
+                    {  
+                            // In the .o file, this should be a relative jump to NULL
+                            // and we'll change it to a jump to a relative jump to the symbol
+                        ASSERT(-word == reloc->r_address);
+                        word = symbolAddress;
+                        jumpIsland = makeJumpIsland(oc,reloc->r_symbolnum,word);
+                       word -= ((long)image) + sect->offset + reloc->r_address;
+                        if(jumpIsland != 0)
+                        {
+                            offsetToJumpIsland = jumpIsland
+                                - (((long)image) + sect->offset + reloc->r_address);
+                        }
+                    }
+                    else
+                    {
+                        word += symbolAddress;
+                    }
                }
-               
+
                if(reloc->r_type == GENERIC_RELOC_VANILLA)
                {
                    *wordPtr = word;
@@ -3072,13 +3571,30 @@ static void relocateSection(char *image,
                        + ((word & (1<<15)) ? 1 : 0);
                    i++; continue;
                }
-               continue;
+               else if(reloc->r_type == PPC_RELOC_BR24)
+               {
+                    if((long)word > (long)0x01FFFFFF || (long)word < (long)0xFFE00000)
+                    {
+                        // The branch offset is too large.
+                        // Therefore, we try to use a jump island.
+                        if(jumpIsland == 0)
+                            barf("unconditional relative branch out of range: "
+                                 "no jump island available");
+
+                        word = offsetToJumpIsland;
+                        if((long)word > (long)0x01FFFFFF || (long)word < (long)0xFFE00000)
+                            barf("unconditional relative branch out of range: "
+                                 "jump island out of range");
+                    }
+                   *wordPtr = (*wordPtr & 0xFC000003) | (word & 0x03FFFFFC);
+                   continue;
+               }
            }
-           fprintf(stderr, "unknown reloc\n");
-           abort();
-           ASSERT(2 + 2 == 5);
+           barf("\nunknown relocation %d",reloc->r_type);
+           return 0;
        }
     }
+    return 1;
 }
 
 static int ocGetNames_MachO(ObjectCode* oc)
@@ -3088,7 +3604,7 @@ static int ocGetNames_MachO(ObjectCode* oc)
     struct load_command *lc = (struct load_command*) (image + sizeof(struct mach_header));
     unsigned i,curSymbol;
     struct segment_command *segLC = NULL;
-    struct section *sections, *la_ptrs = NULL, *nl_ptrs = NULL;
+    struct section *sections;
     struct symtab_command *symLC = NULL;
     struct dysymtab_command *dsymLC = NULL;
     struct nlist *nlist;
@@ -3107,95 +3623,125 @@ static int ocGetNames_MachO(ObjectCode* oc)
        lc = (struct load_command *) ( ((char*)lc) + lc->cmdsize );
     }
 
-    sections = (struct section*) (segLC+1); 
+    sections = (struct section*) (segLC+1);
     nlist = (struct nlist*) (image + symLC->symoff);
 
     for(i=0;i<segLC->nsects;i++)
     {
-       if(!strcmp(sections[i].sectname,"__la_symbol_ptr"))
-           la_ptrs = &sections[i];
-       else if(!strcmp(sections[i].sectname,"__nl_symbol_ptr"))
-           nl_ptrs = &sections[i];
-           
-           // for now, only add __text and __const to the sections table
-       else if(!strcmp(sections[i].sectname,"__text"))
-           addSection(oc, SECTIONKIND_CODE_OR_RODATA, 
+        if(sections[i].size == 0)
+            continue;
+
+        if((sections[i].flags & SECTION_TYPE) == S_ZEROFILL)
+        {
+            char * zeroFillArea = stgCallocBytes(1,sections[i].size,
+                                      "ocGetNames_MachO(common symbols)");
+            sections[i].offset = zeroFillArea - image;
+        }
+
+       if(!strcmp(sections[i].sectname,"__text"))
+           addSection(oc, SECTIONKIND_CODE_OR_RODATA,
                (void*) (image + sections[i].offset),
                (void*) (image + sections[i].offset + sections[i].size));
        else if(!strcmp(sections[i].sectname,"__const"))
-           addSection(oc, SECTIONKIND_RWDATA, 
+           addSection(oc, SECTIONKIND_RWDATA,
                (void*) (image + sections[i].offset),
                (void*) (image + sections[i].offset + sections[i].size));
        else if(!strcmp(sections[i].sectname,"__data"))
-           addSection(oc, SECTIONKIND_RWDATA, 
+           addSection(oc, SECTIONKIND_RWDATA,
+               (void*) (image + sections[i].offset),
+               (void*) (image + sections[i].offset + sections[i].size));
+       else if(!strcmp(sections[i].sectname,"__bss")
+               || !strcmp(sections[i].sectname,"__common"))
+           addSection(oc, SECTIONKIND_RWDATA,
                (void*) (image + sections[i].offset),
                (void*) (image + sections[i].offset + sections[i].size));
+
+        addProddableBlock(oc, (void*) (image + sections[i].offset),
+                                        sections[i].size);
     }
 
        // count external symbols defined here
     oc->n_symbols = 0;
-    for(i=dsymLC->iextdefsym;i<dsymLC->iextdefsym+dsymLC->nextdefsym;i++)
+    if(dsymLC)
     {
-       if((nlist[i].n_type & N_TYPE) == N_SECT)
-           oc->n_symbols++;
+        for(i = dsymLC->iextdefsym;
+            i < dsymLC->iextdefsym + dsymLC->nextdefsym;
+            i++)
+        {
+            if((nlist[i].n_type & N_TYPE) == N_SECT)
+                oc->n_symbols++;
+        }
     }
-    for(i=0;i<symLC->nsyms;i++)
+    if(symLC)
     {
-       if((nlist[i].n_type & N_TYPE) == N_UNDF
+        for(i=0;i<symLC->nsyms;i++)
+        {
+           if((nlist[i].n_type & N_TYPE) == N_UNDF
                && (nlist[i].n_type & N_EXT) && (nlist[i].n_value != 0))
-       {
-           commonSize += nlist[i].n_value;
-           oc->n_symbols++;
-       }
+           {
+               commonSize += nlist[i].n_value;
+               oc->n_symbols++;
+           }
+        }
     }
     oc->symbols = stgMallocBytes(oc->n_symbols * sizeof(char*),
                                   "ocGetNames_MachO(oc->symbols)");
-    
-       // insert symbols into hash table
-    for(i=dsymLC->iextdefsym,curSymbol=0;i<dsymLC->iextdefsym+dsymLC->nextdefsym;i++)
+
+    if(dsymLC)
     {
-       if((nlist[i].n_type & N_TYPE) == N_SECT)
-       {
-           char *nm = image + symLC->stroff + nlist[i].n_un.n_strx;
-           ghciInsertStrHashTable(oc->fileName, symhash, nm, image + 
-               sections[nlist[i].n_sect-1].offset
-               - sections[nlist[i].n_sect-1].addr
-               + nlist[i].n_value);
-           oc->symbols[curSymbol++] = nm;
-       }
-    }
+        // insert symbols into hash table
+        for(i = dsymLC->iextdefsym, curSymbol = 0;
+            i < dsymLC->iextdefsym + dsymLC->nextdefsym;
+            i++)
+        {
+            if((nlist[i].n_type & N_TYPE) == N_SECT)
+            {
+                char *nm = image + symLC->stroff + nlist[i].n_un.n_strx;
+                ghciInsertStrHashTable(oc->fileName, symhash, nm,
+                                        image
+                                        + sections[nlist[i].n_sect-1].offset
+                                        - sections[nlist[i].n_sect-1].addr
+                                        + nlist[i].n_value);
+                oc->symbols[curSymbol++] = nm;
+            }
+        }
     
-       // insert local symbols into lochash
-    for(i=dsymLC->ilocalsym;i<dsymLC->ilocalsym+dsymLC->nlocalsym;i++)
-    {
-       if((nlist[i].n_type & N_TYPE) == N_SECT)
-       {
-           char *nm = image + symLC->stroff + nlist[i].n_un.n_strx;
-           ghciInsertStrHashTable(oc->fileName, oc->lochash, nm, image + 
-               sections[nlist[i].n_sect-1].offset
-               - sections[nlist[i].n_sect-1].addr
-               + nlist[i].n_value);
-       }
+        // insert local symbols into lochash
+        for(i=dsymLC->ilocalsym;i<dsymLC->ilocalsym+dsymLC->nlocalsym;i++)
+        {
+            if((nlist[i].n_type & N_TYPE) == N_SECT)
+            {
+                char *nm = image + symLC->stroff + nlist[i].n_un.n_strx;
+                ghciInsertStrHashTable(oc->fileName, oc->lochash, nm,
+                                        image
+                                        + sections[nlist[i].n_sect-1].offset
+                                        - sections[nlist[i].n_sect-1].addr
+                                        + nlist[i].n_value);
+            }
+        }
     }
 
-    
     commonStorage = stgCallocBytes(1,commonSize,"ocGetNames_MachO(common symbols)");
     commonCounter = (unsigned long)commonStorage;
-    for(i=0;i<symLC->nsyms;i++)
+    if(symLC)
     {
-       if((nlist[i].n_type & N_TYPE) == N_UNDF
-               && (nlist[i].n_type & N_EXT) && (nlist[i].n_value != 0))
-       {
-           char *nm = image + symLC->stroff + nlist[i].n_un.n_strx;
-           unsigned long sz = nlist[i].n_value;
-           
-           nlist[i].n_value = commonCounter;
-           
-           ghciInsertStrHashTable(oc->fileName, symhash, nm, (void*)commonCounter);
-           oc->symbols[curSymbol++] = nm;
-           
-           commonCounter += sz;
-       }
+        for(i=0;i<symLC->nsyms;i++)
+        {
+           if((nlist[i].n_type & N_TYPE) == N_UNDF
+                   && (nlist[i].n_type & N_EXT) && (nlist[i].n_value != 0))
+           {
+               char *nm = image + symLC->stroff + nlist[i].n_un.n_strx;
+               unsigned long sz = nlist[i].n_value;
+
+               nlist[i].n_value = commonCounter;
+
+               ghciInsertStrHashTable(oc->fileName, symhash, nm,
+                                      (void*)commonCounter);
+               oc->symbols[curSymbol++] = nm;
+
+               commonCounter += sz;
+           }
+        }
     }
     return 1;
 }
@@ -3211,7 +3757,6 @@ static int ocResolve_MachO(ObjectCode* oc)
     struct symtab_command *symLC = NULL;
     struct dysymtab_command *dsymLC = NULL;
     struct nlist *nlist;
-    unsigned long *indirectSyms;
 
     for(i=0;i<header->ncmds;i++)
     {
@@ -3223,9 +3768,10 @@ static int ocResolve_MachO(ObjectCode* oc)
            dsymLC = (struct dysymtab_command*) lc;
        lc = (struct load_command *) ( ((char*)lc) + lc->cmdsize );
     }
-    
-    sections = (struct section*) (segLC+1); 
-    nlist = (struct nlist*) (image + symLC->symoff);
+
+    sections = (struct section*) (segLC+1);
+    nlist = symLC ? (struct nlist*) (image + symLC->symoff)
+                  : NULL;
 
     for(i=0;i<segLC->nsects;i++)
     {
@@ -3234,23 +3780,66 @@ static int ocResolve_MachO(ObjectCode* oc)
        else if(!strcmp(sections[i].sectname,"__nl_symbol_ptr"))
            nl_ptrs = &sections[i];
     }
-    
-    indirectSyms = (unsigned long*) (image + dsymLC->indirectsymoff);
 
-    if(la_ptrs)
-       resolveImports(oc,image,symLC,la_ptrs,indirectSyms,nlist);
-    if(nl_ptrs)
-       resolveImports(oc,image,symLC,nl_ptrs,indirectSyms,nlist);
+    if(dsymLC)
+    {
+        unsigned long *indirectSyms
+            = (unsigned long*) (image + dsymLC->indirectsymoff);
+
+        if(la_ptrs)
+            if(!resolveImports(oc,image,symLC,la_ptrs,indirectSyms,nlist))
+                return 0;
+        if(nl_ptrs)
+            if(!resolveImports(oc,image,symLC,nl_ptrs,indirectSyms,nlist))
+                return 0;
+    }
     
     for(i=0;i<segLC->nsects;i++)
     {
-       relocateSection(image,symLC,nlist,sections,&sections[i]);
+       if(!relocateSection(oc,image,symLC,nlist,segLC->nsects,sections,&sections[i]))
+           return 0;
     }
 
     /* Free the local symbol table; we won't need it again. */
     freeHashTable(oc->lochash, NULL);
     oc->lochash = NULL;
+
+#if defined (powerpc_TARGET_ARCH)
+    ocFlushInstructionCache( oc );
+#endif
+
     return 1;
 }
 
+/*
+ * The Mach-O object format uses leading underscores. But not everywhere.
+ * There is a small number of runtime support functions defined in
+ * libcc_dynamic.a whose name does not have a leading underscore.
+ * As a consequence, we can't get their address from C code.
+ * We have to use inline assembler just to take the address of a function.
+ * Yuck.
+ */
+
+static void machoInitSymbolsWithoutUnderscore()
+{
+    extern void* symbolsWithoutUnderscore[];
+    void **p = symbolsWithoutUnderscore;
+    __asm__ volatile(".data\n_symbolsWithoutUnderscore:");
+
+#undef Sym
+#define Sym(x)  \
+    __asm__ volatile(".long " # x);
+
+    RTS_MACHO_NOUNDERLINE_SYMBOLS
+
+    __asm__ volatile(".text");
+    
+#undef Sym
+#define Sym(x)  \
+    ghciInsertStrHashTable("(GHCi built-in symbols)", symhash, #x, *p++);
+    
+    RTS_MACHO_NOUNDERLINE_SYMBOLS
+    
+#undef Sym
+}
 #endif