#include "HsFFI.h"
#include "sm/Storage.h"
+#include "Stats.h"
#include "Hash.h"
#include "LinkerInternals.h"
#include "RtsUtils.h"
#include "posix/Signals.h"
#endif
+#if defined(mingw32_HOST_OS)
+// get protos for is*()
+#include <ctype.h>
+#endif
+
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include <stdlib.h>
#include <string.h>
+#include <stdio.h>
+#include <assert.h>
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#include <sys/wait.h>
#endif
-#if defined(ia64_HOST_ARCH) || defined(linux_HOST_OS) || defined(freebsd_HOST_OS) || defined(netbsd_HOST_OS) || defined(openbsd_HOST_OS)
+#if defined(linux_HOST_OS) || defined(freebsd_HOST_OS) || defined(dragonfly_HOST_OS) || defined(netbsd_HOST_OS) || defined(openbsd_HOST_OS) || defined(darwin_HOST_OS)
#define USE_MMAP
#include <fcntl.h>
#include <sys/mman.h>
-#if defined(linux_HOST_OS) || defined(freebsd_HOST_OS) || defined(netbsd_HOST_OS) || defined(openbsd_HOST_OS)
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
-#endif
#endif
-#if defined(linux_HOST_OS) || defined(solaris2_HOST_OS) || defined(freebsd_HOST_OS) || defined(netbsd_HOST_OS) || defined(openbsd_HOST_OS)
+#if defined(linux_HOST_OS) || defined(solaris2_HOST_OS) || defined(freebsd_HOST_OS) || defined(dragonfly_HOST_OS) || defined(netbsd_HOST_OS) || defined(openbsd_HOST_OS)
# define OBJFORMAT_ELF
+# include <regex.h> // regex is already used by dlopen() so this is OK
+ // to use here without requiring an additional lib
#elif defined(cygwin32_HOST_OS) || defined (mingw32_HOST_OS)
# define OBJFORMAT_PEi386
# include <windows.h>
# include <math.h>
#elif defined(darwin_HOST_OS)
# define OBJFORMAT_MACHO
+# include <regex.h>
# include <mach-o/loader.h>
# include <mach-o/nlist.h>
# include <mach-o/reloc.h>
#endif
#endif
+#if defined(x86_64_HOST_ARCH) && defined(darwin_HOST_OS)
+#define ALWAYS_PIC
+#endif
+
/* Hash table mapping symbol names to Symbol */
static /*Str*/HashTable *symhash;
static int ocGetNames_MachO ( ObjectCode* oc );
static int ocResolve_MachO ( ObjectCode* oc );
+#ifndef USE_MMAP
static int machoGetMisalignment( FILE * );
+#endif
#if defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH)
static int ocAllocateSymbolExtras_MachO ( ObjectCode* oc );
#endif
* We pick a default address based on the OS, but also make this
* configurable via an RTS flag (+RTS -xm)
*/
-#if defined(x86_64_HOST_ARCH)
+#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH)
#if defined(MAP_32BIT)
// Try to use MAP_32BIT
SymI_HasProto(strncpy) \
SymI_HasProto(abort) \
SymI_NeedsProto(_alloca) \
- SymI_NeedsProto(isxdigit) \
- SymI_NeedsProto(isupper) \
- SymI_NeedsProto(ispunct) \
- SymI_NeedsProto(islower) \
- SymI_NeedsProto(isspace) \
- SymI_NeedsProto(isprint) \
- SymI_NeedsProto(isdigit) \
- SymI_NeedsProto(iscntrl) \
- SymI_NeedsProto(isalpha) \
- SymI_NeedsProto(isalnum) \
- SymI_NeedsProto(isascii) \
+ SymI_HasProto(isxdigit) \
+ SymI_HasProto(isupper) \
+ SymI_HasProto(ispunct) \
+ SymI_HasProto(islower) \
+ SymI_HasProto(isspace) \
+ SymI_HasProto(isprint) \
+ SymI_HasProto(isdigit) \
+ SymI_HasProto(iscntrl) \
+ SymI_HasProto(isalpha) \
+ SymI_HasProto(isalnum) \
+ SymI_HasProto(isascii) \
RTS___MINGW_VFPRINTF_SYM \
SymI_HasProto(strcmp) \
SymI_HasProto(memmove) \
SymI_NeedsProto(closedir)
#endif
-#if defined(darwin_TARGET_OS) && HAVE_PRINTF_LDBLSTUB
+#if defined(darwin_HOST_OS) && HAVE_PRINTF_LDBLSTUB
#define RTS_DARWIN_ONLY_SYMBOLS \
SymI_NeedsProto(asprintf$LDBLStub) \
SymI_NeedsProto(err$LDBLStub) \
#if !defined(mingw32_HOST_OS)
#define RTS_USER_SIGNALS_SYMBOLS \
- SymI_HasProto(setIOManagerPipe) \
+ SymI_HasProto(setIOManagerControlFd) \
+ SymI_HasProto(setIOManagerWakeupFd) \
+ SymI_HasProto(ioManagerWakeup) \
SymI_HasProto(blockUserSignals) \
SymI_HasProto(unblockUserSignals)
#else
#define RTS_USER_SIGNALS_SYMBOLS \
+ SymI_HasProto(ioManagerWakeup) \
SymI_HasProto(sendIOManagerEvent) \
SymI_HasProto(readIOManagerEvent) \
SymI_HasProto(getIOManagerEvent) \
SymI_HasProto(RET_SEMI_loads_avoided)
+// On most platforms, the garbage collector rewrites references
+// to small integer and char objects to a set of common, shared ones.
+//
+// We don't do this when compiling to Windows DLLs at the moment because
+// it doesn't support cross package data references well.
+//
+#if defined(__PIC__) && defined(mingw32_HOST_OS)
+#define RTS_INTCHAR_SYMBOLS
+#else
+#define RTS_INTCHAR_SYMBOLS \
+ SymI_HasProto(stg_CHARLIKE_closure) \
+ SymI_HasProto(stg_INTLIKE_closure)
+#endif
+
+
#define RTS_SYMBOLS \
Maybe_Stable_Names \
RTS_TICKY_SYMBOLS \
SymI_HasProto(debugBelch) \
SymI_HasProto(errorBelch) \
SymI_HasProto(sysErrorBelch) \
- SymI_HasProto(stg_asyncExceptionsBlockedzh) \
- SymI_HasProto(stg_blockAsyncExceptionszh) \
+ SymI_HasProto(stg_getMaskingStatezh) \
+ SymI_HasProto(stg_maskAsyncExceptionszh) \
+ SymI_HasProto(stg_maskUninterruptiblezh) \
SymI_HasProto(stg_catchzh) \
SymI_HasProto(stg_catchRetryzh) \
SymI_HasProto(stg_catchSTMzh) \
SymI_HasProto(forkOS_createThread) \
SymI_HasProto(freeHaskellFunctionPtr) \
SymI_HasProto(getOrSetTypeableStore) \
- SymI_HasProto(getOrSetSignalHandlerStore) \
+ SymI_HasProto(getOrSetGHCConcSignalSignalHandlerStore) \
+ SymI_HasProto(getOrSetGHCConcWindowsPendingDelaysStore) \
+ SymI_HasProto(getOrSetGHCConcWindowsIOManagerThreadStore) \
+ SymI_HasProto(getOrSetGHCConcWindowsProddingStore) \
+ SymI_HasProto(getOrSetSystemEventThreadEventManagerStore) \
+ SymI_HasProto(getOrSetSystemEventThreadIOManagerThreadStore) \
SymI_HasProto(genSymZh) \
SymI_HasProto(genericRaise) \
SymI_HasProto(getProgArgv) \
SymI_HasProto(stg_unpackClosurezh) \
SymI_HasProto(stg_getApStackValzh) \
SymI_HasProto(stg_getSparkzh) \
+ SymI_HasProto(stg_numSparkszh) \
SymI_HasProto(stg_isCurrentThreadBoundzh) \
SymI_HasProto(stg_isEmptyMVarzh) \
SymI_HasProto(stg_killThreadzh) \
SymI_HasProto(stable_ptr_table) \
SymI_HasProto(stackOverflow) \
SymI_HasProto(stg_CAF_BLACKHOLE_info) \
+ SymI_HasProto(stg_BLACKHOLE_info) \
SymI_HasProto(__stg_EAGER_BLACKHOLE_info) \
+ SymI_HasProto(stg_BLOCKING_QUEUE_CLEAN_info) \
+ SymI_HasProto(stg_BLOCKING_QUEUE_DIRTY_info) \
SymI_HasProto(startTimer) \
- SymI_HasProto(stg_CHARLIKE_closure) \
SymI_HasProto(stg_MVAR_CLEAN_info) \
SymI_HasProto(stg_MVAR_DIRTY_info) \
SymI_HasProto(stg_IND_STATIC_info) \
- SymI_HasProto(stg_INTLIKE_closure) \
SymI_HasProto(stg_ARR_WORDS_info) \
SymI_HasProto(stg_MUT_ARR_PTRS_DIRTY_info) \
SymI_HasProto(stg_MUT_ARR_PTRS_FROZEN_info) \
SymI_HasProto(stg_sel_8_upd_info) \
SymI_HasProto(stg_sel_9_upd_info) \
SymI_HasProto(stg_upd_frame_info) \
+ SymI_HasProto(stg_bh_upd_frame_info) \
SymI_HasProto(suspendThread) \
SymI_HasProto(stg_takeMVarzh) \
SymI_HasProto(stg_threadStatuszh) \
SymI_HasProto(stg_tryPutMVarzh) \
SymI_HasProto(stg_tryTakeMVarzh) \
- SymI_HasProto(stg_unblockAsyncExceptionszh) \
+ SymI_HasProto(stg_unmaskAsyncExceptionszh) \
SymI_HasProto(unloadObj) \
SymI_HasProto(stg_unsafeThawArrayzh) \
SymI_HasProto(stg_waitReadzh) \
SymI_HasProto(stg_writeTVarzh) \
SymI_HasProto(stg_yieldzh) \
SymI_NeedsProto(stg_interp_constr_entry) \
- SymI_HasProto(alloc_blocks) \
SymI_HasProto(alloc_blocks_lim) \
- SymI_HasProto(allocateLocal) \
+ SymI_HasProto(g0) \
+ SymI_HasProto(allocate) \
SymI_HasProto(allocateExec) \
SymI_HasProto(freeExec) \
SymI_HasProto(getAllocations) \
SymI_HasProto(n_capabilities) \
SymI_HasProto(stg_traceCcszh) \
SymI_HasProto(stg_traceEventzh) \
- RTS_USER_SIGNALS_SYMBOLS
+ RTS_USER_SIGNALS_SYMBOLS \
+ RTS_INTCHAR_SYMBOLS
// 64-bit support functions in libgcc.a
SymI_NeedsProto(__muldi3) \
SymI_NeedsProto(__ashldi3) \
SymI_NeedsProto(__ashrdi3) \
- SymI_NeedsProto(__lshrdi3) \
- SymI_NeedsProto(__eprintf)
+ SymI_NeedsProto(__lshrdi3)
#else
#define RTS_LIBGCC_SYMBOLS
#endif
-/* NOTE [io-manager-ghci]
-
- When GHCi loads the base package, it gets another copy of the CAFs
- in GHC.Conc that record the IO manager's ThreadId, and the blocking
- queues, so we get another IO manager. This is bad enough, but what
- is worse is that GHCi by default reverts all CAFs on every :load,
- so we'll get *another* IO manager thread (and an associated pipe)
- every time the user does :load. Miraculously, this actually
- manages to just about work in GHC 6.10 and earlier, but broke when
- I tried to fix #1185 (restarting the IO manager after a fork()).
-
- To work around it and ensure that we only have a single IO manager,
- we map the CAFs in the dynamically-loaded GHC.Conc to the
- statically-linked GHC.Conc. This is an ugly hack, but it's the
- least ugly hack that I could think of (SDM 3/11/2009)
-*/
-
-#define RTS_GHC_CONC_SYMBOLS \
- SymI_NeedsProto(base_GHCziConc_pendingDelays_closure) \
- SymI_NeedsProto(base_GHCziConc_pendingEvents_closure) \
- SymI_NeedsProto(base_GHCziConc_ioManagerThread_closure)
-
-#ifdef mingw32_HOST_OS
-#define RTS_GHC_CONC_OS_SYMBOLS /* empty */
-#else
-#define RTS_GHC_CONC_OS_SYMBOLS \
- SymI_NeedsProto(base_GHCziConc_prodding_closure) \
- SymI_NeedsProto(base_GHCziConc_sync_closure) \
- SymI_NeedsProto(base_GHCziConc_stick_closure)
-#endif
-
#if defined(darwin_HOST_OS) && defined(powerpc_HOST_ARCH)
// Symbols that don't have a leading underscore
// on Mac OS X. They have to receive special treatment,
/* entirely bogus claims about types of these symbols */
#define SymI_NeedsProto(vvv) extern void vvv(void);
-#if defined(__PIC__) && defined(mingw32_TARGET_OS)
+#if defined(__PIC__) && defined(mingw32_HOST_OS)
#define SymE_HasProto(vvv) SymE_HasProto(vvv);
#define SymE_NeedsProto(vvv) extern void _imp__ ## vvv (void);
#else
RTS_DARWIN_ONLY_SYMBOLS
RTS_LIBGCC_SYMBOLS
RTS_LIBFFI_SYMBOLS
-RTS_GHC_CONC_SYMBOLS
-RTS_GHC_CONC_OS_SYMBOLS
#undef SymI_NeedsProto
#undef SymI_HasProto
#undef SymI_HasProto_redirect
RTS_DARWIN_ONLY_SYMBOLS
RTS_LIBGCC_SYMBOLS
RTS_LIBFFI_SYMBOLS
- RTS_GHC_CONC_SYMBOLS
- RTS_GHC_CONC_OS_SYMBOLS
#if defined(darwin_HOST_OS) && defined(i386_HOST_ARCH)
// dyld stub code contains references to this,
// but it should never be called because we treat
void *data
)
{
-#define GHC_CONC "base_GHCziConc"
-
- if (lookupHashTable(table, (StgWord)key) == NULL)
- {
+ if (lookupHashTable(table, (StgWord)key) == NULL)
+ {
insertStrHashTable(table, (StgWord)key, data);
return;
- }
- if (strncmp(key, GHC_CONC, strlen(GHC_CONC)) == 0) {
- /* see NOTE [io-manager-ghci] */
- return;
- }
- debugBelch(
+ }
+ debugBelch(
"\n\n"
"GHCi runtime linker: fatal error: I found a duplicate definition for symbol\n"
" %s\n"
"\n",
(char*)key,
obj_name
- );
- exit(1);
+ );
+ exit(1);
}
/* -----------------------------------------------------------------------------
* initialize the object linker
#if defined(OBJFORMAT_ELF) || defined(OBJFORMAT_MACHO)
static void *dl_prog_handle;
+static regex_t re_invalid;
+static regex_t re_realso;
+#ifdef THREADED_RTS
+static Mutex dl_mutex; // mutex to protect dlopen/dlerror critical section
+#endif
#endif
void
initLinker( void )
{
RtsSymbolVal *sym;
+#if defined(OBJFORMAT_ELF) || defined(OBJFORMAT_MACHO)
+ int compileResult;
+#endif
/* Make initLinker idempotent, so we can call it
before evey relevant operation; that means we
linker_init_done = 1;
}
+#if defined(THREADED_RTS) && (defined(OBJFORMAT_ELF) || defined(OBJFORMAT_MACHO))
+ initMutex(&dl_mutex);
+#endif
stablehash = allocStrHashTable();
symhash = allocStrHashTable();
# else
dl_prog_handle = dlopen(NULL, RTLD_LAZY);
# endif /* RTLD_DEFAULT */
+
+ compileResult = regcomp(&re_invalid,
+ "(([^ \t()])+\\.so([^ \t:()])*):([ \t])*invalid ELF header",
+ REG_EXTENDED);
+ ASSERT( compileResult == 0 );
+ compileResult = regcomp(&re_realso,
+ "GROUP *\\( *(([^ )])+)",
+ REG_EXTENDED);
+ ASSERT( compileResult == 0 );
# endif
-#if defined(x86_64_HOST_ARCH)
+#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH)
if (RtsFlags.MiscFlags.linkerMemBase != 0) {
// User-override for mmap_32bit_base
mmap_32bit_base = (void*)RtsFlags.MiscFlags.linkerMemBase;
#endif
}
+void
+exitLinker( void ) {
+#if defined(OBJFORMAT_ELF) || defined(OBJFORMAT_MACHO)
+ if (linker_init_done == 1) {
+ regfree(&re_invalid);
+ regfree(&re_realso);
+#ifdef THREADED_RTS
+ closeMutex(&dl_mutex);
+#endif
+ }
+#endif
+}
+
/* -----------------------------------------------------------------------------
* Loading DLL or .so dynamic libraries
* -----------------------------------------------------------------------------
static OpenedDLL* opened_dlls = NULL;
#endif
-const char *
-addDLL( char *dll_name )
-{
# if defined(OBJFORMAT_ELF) || defined(OBJFORMAT_MACHO)
- /* ------------------- ELF DLL loader ------------------- */
+
+static const char *
+internal_dlopen(const char *dll_name)
+{
void *hdl;
const char *errmsg;
-
- initLinker();
+ char *errmsg_copy;
// omitted: RTLD_NOW
// see http://www.haskell.org/pipermail/cvs-ghc/2007-September/038570.html
- hdl= dlopen(dll_name, RTLD_LAZY | RTLD_GLOBAL);
+ IF_DEBUG(linker,
+ debugBelch("internal_dlopen: dll_name = '%s'\n", dll_name));
+
+ //-------------- Begin critical section ------------------
+ // This critical section is necessary because dlerror() is not
+ // required to be reentrant (see POSIX -- IEEE Std 1003.1-2008)
+ // Also, the error message returned must be copied to preserve it
+ // (see POSIX also)
+ ACQUIRE_LOCK(&dl_mutex);
+ hdl = dlopen(dll_name, RTLD_LAZY | RTLD_GLOBAL);
+
+ errmsg = NULL;
if (hdl == NULL) {
/* dlopen failed; return a ptr to the error msg. */
errmsg = dlerror();
if (errmsg == NULL) errmsg = "addDLL: unknown error";
- return errmsg;
- } else {
+ errmsg_copy = stgMallocBytes(strlen(errmsg)+1, "addDLL");
+ strcpy(errmsg_copy, errmsg);
+ errmsg = errmsg_copy;
+ }
+ RELEASE_LOCK(&dl_mutex);
+ //--------------- End critical section -------------------
+
+ return errmsg;
+}
+# endif
+
+const char *
+addDLL( char *dll_name )
+{
+# if defined(OBJFORMAT_ELF) || defined(OBJFORMAT_MACHO)
+ /* ------------------- ELF DLL loader ------------------- */
+
+#define NMATCH 5
+ regmatch_t match[NMATCH];
+ const char *errmsg;
+ FILE* fp;
+ size_t match_length;
+#define MAXLINE 1000
+ char line[MAXLINE];
+ int result;
+
+ initLinker();
+
+ IF_DEBUG(linker, debugBelch("addDLL: dll_name = '%s'\n", dll_name));
+ errmsg = internal_dlopen(dll_name);
+
+ if (errmsg == NULL) {
return NULL;
}
- /*NOTREACHED*/
+
+ // GHC Trac ticket #2615
+ // On some systems (e.g., Gentoo Linux) dynamic files (e.g. libc.so)
+ // contain linker scripts rather than ELF-format object code. This
+ // code handles the situation by recognizing the real object code
+ // file name given in the linker script.
+ //
+ // If an "invalid ELF header" error occurs, it is assumed that the
+ // .so file contains a linker script instead of ELF object code.
+ // In this case, the code looks for the GROUP ( ... ) linker
+ // directive. If one is found, the first file name inside the
+ // parentheses is treated as the name of a dynamic library and the
+ // code attempts to dlopen that file. If this is also unsuccessful,
+ // an error message is returned.
+
+ // see if the error message is due to an invalid ELF header
+ IF_DEBUG(linker, debugBelch("errmsg = '%s'\n", errmsg));
+ result = regexec(&re_invalid, errmsg, (size_t) NMATCH, match, 0);
+ IF_DEBUG(linker, debugBelch("result = %i\n", result));
+ if (result == 0) {
+ // success -- try to read the named file as a linker script
+ match_length = (size_t) stg_min((match[1].rm_eo - match[1].rm_so),
+ MAXLINE-1);
+ strncpy(line, (errmsg+(match[1].rm_so)),match_length);
+ line[match_length] = '\0'; // make sure string is null-terminated
+ IF_DEBUG(linker, debugBelch ("file name = '%s'\n", line));
+ if ((fp = fopen(line, "r")) == NULL) {
+ return errmsg; // return original error if open fails
+ }
+ // try to find a GROUP ( ... ) command
+ while (fgets(line, MAXLINE, fp) != NULL) {
+ IF_DEBUG(linker, debugBelch("input line = %s", line));
+ if (regexec(&re_realso, line, (size_t) NMATCH, match, 0) == 0) {
+ // success -- try to dlopen the first named file
+ IF_DEBUG(linker, debugBelch("match%s\n",""));
+ line[match[1].rm_eo] = '\0';
+ errmsg = internal_dlopen(line+match[1].rm_so);
+ break;
+ }
+ // if control reaches here, no GROUP ( ... ) directive was found
+ // and the original error message is returned to the caller
+ }
+ fclose(fp);
+ }
+ return errmsg;
# elif defined(OBJFORMAT_PEi386)
/* ------------------- Win32 DLL loader ------------------- */
# elif defined(OBJFORMAT_PEi386)
void* sym;
- sym = lookupSymbolInDLLs(lbl);
+ sym = lookupSymbolInDLLs((unsigned char*)lbl);
if (sym != NULL) { return sym; };
// Also try looking up the symbol without the @N suffix. Some
// DLLs have the suffixes on their symbols, some don't.
- zapTrailingAtSign ( lbl );
- sym = lookupSymbolInDLLs(lbl);
+ zapTrailingAtSign ( (unsigned char*)lbl );
+ sym = lookupSymbolInDLLs((unsigned char*)lbl);
if (sym != NULL) { return sym; };
return NULL;
pagesize = getpagesize();
size = ROUND_UP(bytes, pagesize);
-#if defined(x86_64_HOST_ARCH)
+#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH)
mmap_again:
if (mmap_32bit_base != 0) {
stg_exit(EXIT_FAILURE);
}
-#if defined(x86_64_HOST_ARCH)
+#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH)
if (mmap_32bit_base != 0) {
if (result == map_addr) {
mmap_32bit_base = (StgWord8*)map_addr + size;
} else {
if ((W_)result > 0x80000000) {
// oops, we were given memory over 2Gb
-#if defined(freebsd_HOST_OS)
+#if defined(freebsd_HOST_OS) || defined(dragonfly_HOST_OS)
// Some platforms require MAP_FIXED. This is normally
// a bad idea, because MAP_FIXED will overwrite
// existing mappings.
#else
FILE *f;
#endif
+ IF_DEBUG(linker, debugBelch("loadObj %s\n", path));
initLinker();
/* debugBelch("loadObj %s\n", path ); */
# endif
r = stat(path, &st);
- if (r == -1) { return 0; }
+ if (r == -1) {
+ IF_DEBUG(linker, debugBelch("File doesn't exist\n"));
+ return 0;
+ }
/* sigh, strdup() isn't a POSIX function, so do it the long way */
oc->fileName = stgMallocBytes( strlen(path)+1, "loadObj" );
# if defined(OBJFORMAT_MACHO) && (defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH))
r = ocAllocateSymbolExtras_MachO ( oc );
- if (!r) { return r; }
+ if (!r) {
+ IF_DEBUG(linker, debugBelch("ocAllocateSymbolExtras_MachO failed\n"));
+ return r;
+ }
# elif defined(OBJFORMAT_ELF) && (defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH))
r = ocAllocateSymbolExtras_ELF ( oc );
- if (!r) { return r; }
+ if (!r) {
+ IF_DEBUG(linker, debugBelch("ocAllocateSymbolExtras_ELF failed\n"));
+ return r;
+ }
#endif
/* verify the in-memory image */
# else
barf("loadObj: no verify method");
# endif
- if (!r) { return r; }
+ if (!r) {
+ IF_DEBUG(linker, debugBelch("ocVerifyImage_* failed\n"));
+ return r;
+ }
/* build the symbol list for this image */
# if defined(OBJFORMAT_ELF)
# else
barf("loadObj: no getNames method");
# endif
- if (!r) { return r; }
+ if (!r) {
+ IF_DEBUG(linker, debugBelch("ocGetNames_* failed\n"));
+ return r;
+ }
/* loaded, but not resolved yet */
oc->status = OBJECT_LOADED;
* PowerPC specifics (instruction cache flushing)
* ------------------------------------------------------------------------*/
-#ifdef powerpc_TARGET_ARCH
+#ifdef powerpc_HOST_ARCH
/*
ocFlushInstructionCache
{
if (name[0]==0 && name[1]==0 && name[2]==0 && name[3]==0) {
UInt32 strtab_offset = * (UInt32*)(name+4);
- strncpy ( dst, strtab+strtab_offset, dstSize );
+ strncpy ( (char*)dst, (char*)strtab+strtab_offset, dstSize );
dst[dstSize-1] = 0;
} else {
int i = 0;
*/
newstr = stgMallocBytes(9, "cstring_from_COFF_symbol_name");
ASSERT(newstr);
- strncpy(newstr,name,8);
+ strncpy((char*)newstr,(char*)name,8);
newstr[8] = 0;
return newstr;
}
/* Just compares the short names (first 8 chars) */
static COFF_section *
-findPEi386SectionCalled ( ObjectCode* oc, char* name )
+findPEi386SectionCalled ( ObjectCode* oc, UChar* name )
{
int i;
COFF_header* hdr
a Rule that governs whether an initial '_' *should always* be
stripped off when mapping from import lib name to the DLL name.
*/
- sym = GetProcAddress(o_dll->instance, (lbl+1));
+ sym = GetProcAddress(o_dll->instance, (char*)(lbl+1));
if (sym != NULL) {
/*debugBelch("found %s in %s\n", lbl+1,o_dll->name);*/
return sym;
}
}
- sym = GetProcAddress(o_dll->instance, lbl);
+ sym = GetProcAddress(o_dll->instance, (char*)lbl);
if (sym != NULL) {
/*debugBelch("found %s in %s\n", lbl,o_dll->name);*/
return sym;
COFF_section* sectab_i
= (COFF_section*)
myindex ( sizeof_COFF_section, sectab, i );
- if (0 != strcmp(sectab_i->Name, ".bss")) continue;
+ if (0 != strcmp((char*)sectab_i->Name, ".bss")) continue;
/* sof 10/05: the PE spec text isn't too clear regarding what
* the SizeOfRawData field is supposed to hold for object
* file sections containing just uninitialized data -- for executables,
kind = SECTIONKIND_CODE_OR_RODATA;
# endif
- if (0==strcmp(".text",sectab_i->Name) ||
- 0==strcmp(".rdata",sectab_i->Name)||
- 0==strcmp(".rodata",sectab_i->Name))
+ if (0==strcmp(".text",(char*)sectab_i->Name) ||
+ 0==strcmp(".rdata",(char*)sectab_i->Name)||
+ 0==strcmp(".rodata",(char*)sectab_i->Name))
kind = SECTIONKIND_CODE_OR_RODATA;
- if (0==strcmp(".data",sectab_i->Name) ||
- 0==strcmp(".bss",sectab_i->Name))
+ if (0==strcmp(".data",(char*)sectab_i->Name) ||
+ 0==strcmp(".bss",(char*)sectab_i->Name))
kind = SECTIONKIND_RWDATA;
ASSERT(sectab_i->SizeOfRawData == 0 || sectab_i->VirtualSize == 0);
if (kind == SECTIONKIND_OTHER
/* Ignore sections called which contain stabs debugging
information. */
- && 0 != strcmp(".stab", sectab_i->Name)
- && 0 != strcmp(".stabstr", sectab_i->Name)
+ && 0 != strcmp(".stab", (char*)sectab_i->Name)
+ && 0 != strcmp(".stabstr", (char*)sectab_i->Name)
/* ignore constructor section for now */
- && 0 != strcmp(".ctors", sectab_i->Name)
+ && 0 != strcmp(".ctors", (char*)sectab_i->Name)
/* ignore section generated from .ident */
- && 0!= strcmp("/4", sectab_i->Name)
+ && 0!= strcmp("/4", (char*)sectab_i->Name)
/* ignore unknown section that appeared in gcc 3.4.5(?) */
- && 0!= strcmp(".reloc", sectab_i->Name)
+ && 0!= strcmp(".reloc", (char*)sectab_i->Name)
) {
errorBelch("Unknown PEi386 section name `%s' (while processing: %s)", sectab_i->Name, oc->fileName);
return 0;
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);
+ oc->symbols[i] = (char*)sname;
+ ghciInsertStrHashTable(oc->fileName, symhash, (char*)sname, addr);
} else {
# if 0
debugBelch(
/* ToDo: should be variable-sized? But is at least safe in the
sense of buffer-overrun-proof. */
- char symbol[1000];
+ UChar symbol[1000];
/* debugBelch("resolving for %s\n", oc->fileName); */
hdr = (COFF_header*)(oc->image);
/* Ignore sections called which contain stabs debugging
information. */
- if (0 == strcmp(".stab", sectab_i->Name)
- || 0 == strcmp(".stabstr", sectab_i->Name)
- || 0 == strcmp(".ctors", sectab_i->Name))
+ if (0 == strcmp(".stab", (char*)sectab_i->Name)
+ || 0 == strcmp(".stabstr", (char*)sectab_i->Name)
+ || 0 == strcmp(".ctors", (char*)sectab_i->Name))
continue;
if ( sectab_i->Characteristics & MYIMAGE_SCN_LNK_NRELOC_OVFL ) {
+ sym->Value);
} else {
copyName ( sym->Name, strtab, symbol, 1000-1 );
- S = (UInt32) lookupSymbol( symbol );
+ S = (UInt32) lookupSymbol( (char*)symbol );
if ((void*)S != NULL) goto foundit;
errorBelch("%s: unknown symbol `%s'", oc->fileName, symbol);
return 0;
#define Elf_Sym Elf64_Sym
#define Elf_Rel Elf64_Rel
#define Elf_Rela Elf64_Rela
+#ifndef ELF_ST_TYPE
#define ELF_ST_TYPE ELF64_ST_TYPE
+#endif
+#ifndef ELF_ST_BIND
#define ELF_ST_BIND ELF64_ST_BIND
+#endif
+#ifndef ELF_R_TYPE
#define ELF_R_TYPE ELF64_R_TYPE
+#endif
+#ifndef ELF_R_SYM
#define ELF_R_SYM ELF64_R_SYM
+#endif
#else
#define ELFCLASS ELFCLASS32
#define Elf_Addr Elf32_Addr
case R_X86_64_PC32:
{
+#if defined(ALWAYS_PIC)
+ barf("R_X86_64_PC32 relocation, but ALWAYS_PIC.");
+#else
StgInt64 off = value - P;
if (off >= 0x7fffffffL || off < -0x80000000L) {
#if X86_64_ELF_NONPIC_HACK
#endif
}
*(Elf64_Word *)P = (Elf64_Word)off;
+#endif
break;
}
}
case R_X86_64_32:
+#if defined(ALWAYS_PIC)
+ barf("R_X86_64_32 relocation, but ALWAYS_PIC.");
+#else
if (value >= 0x7fffffffL) {
#if X86_64_ELF_NONPIC_HACK
StgInt64 pltAddress = (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S)
#endif
}
*(Elf64_Word *)P = (Elf64_Word)value;
+#endif
break;
case R_X86_64_32S:
+#if defined(ALWAYS_PIC)
+ barf("R_X86_64_32S relocation, but ALWAYS_PIC.");
+#else
if ((StgInt64)value > 0x7fffffffL || (StgInt64)value < -0x80000000L) {
#if X86_64_ELF_NONPIC_HACK
StgInt64 pltAddress = (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S)
#endif
}
*(Elf64_Sword *)P = (Elf64_Sword)value;
+#endif
break;
case R_X86_64_GOTPCREL:
case R_X86_64_PLT32:
{
+#if defined(ALWAYS_PIC)
+ barf("R_X86_64_PLT32 relocation, but ALWAYS_PIC.");
+#else
StgInt64 off = value - P;
if (off >= 0x7fffffffL || off < -0x80000000L) {
StgInt64 pltAddress = (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S)
off = pltAddress + A - P;
}
*(Elf64_Word *)P = (Elf64_Word)off;
+#endif
break;
}
#endif
char *image = (char*) oc->image;
struct mach_header *header = (struct mach_header*) image;
-#if x86_64_TARGET_ARCH || powerpc64_TARGET_ARCH
- if(header->magic != MH_MAGIC_64)
+#if x86_64_HOST_ARCH || powerpc64_HOST_ARCH
+ if(header->magic != MH_MAGIC_64) {
+ errorBelch("%s: Bad magic. Expected: %08x, got: %08x.\n",
+ oc->fileName, MH_MAGIC_64, header->magic);
return 0;
+ }
#else
- if(header->magic != MH_MAGIC)
+ if(header->magic != MH_MAGIC) {
+ errorBelch("%s: Bad magic. Expected: %08x, got: %08x.\n",
+ oc->fileName, MH_MAGIC, header->magic);
return 0;
+ }
#endif
// FIXME: do some more verifying here
return 1;
thing += value;
break;
case X86_64_RELOC_SIGNED:
+ case X86_64_RELOC_SIGNED_1:
+ case X86_64_RELOC_SIGNED_2:
+ case X86_64_RELOC_SIGNED_4:
ASSERT(reloc->r_pcrel);
thing += value - baseValue;
break;
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)
+ || scat->r_type == PPC_RELOC_HA16_SECTDIFF
+ || scat->r_type == PPC_RELOC_LOCAL_SECTDIFF)
#else
else if(scat->r_type == GENERIC_RELOC_SECTDIFF
|| scat->r_type == GENERIC_RELOC_LOCAL_SECTDIFF)
}
#endif
else
- continue; // ignore the others
+ {
+ barf ("Don't know how to handle this Mach-O "
+ "scattered relocation entry: "
+ "object file %s; entry type %ld; "
+ "address %#lx\n",
+ oc->fileName, scat->r_type, scat->r_address);
+ return 0;
+ }
#ifdef powerpc_HOST_ARCH
if(scat->r_type == GENERIC_RELOC_VANILLA
}
#endif
}
+ else
+ {
+ barf("Can't handle Mach-O scattered relocation entry "
+ "with this r_length tag: "
+ "object file %s; entry type %ld; "
+ "r_length tag %ld; address %#lx\n",
+ oc->fileName, scat->r_type, scat->r_length,
+ scat->r_address);
+ return 0;
+ }
+ }
+ else /* scat->r_pcrel */
+ {
+ barf("Don't know how to handle *PC-relative* Mach-O "
+ "scattered relocation entry: "
+ "object file %s; entry type %ld; address %#lx\n",
+ oc->fileName, scat->r_type, scat->r_address);
+ return 0;
}
- continue; // FIXME: I hope it's OK to ignore all the others.
}
- else
+ else /* !(relocs[i].r_address & R_SCATTERED) */
{
struct relocation_info *reloc = &relocs[i];
if(reloc->r_pcrel && !reloc->r_extern)
word = (word & 0x03FFFFFC) | ((word & 0x02000000) ? 0xFC000000 : 0);
}
#endif
+ else
+ {
+ barf("Can't handle this Mach-O relocation entry "
+ "(not scattered): "
+ "object file %s; entry type %ld; address %#lx\n",
+ oc->fileName, reloc->r_type, reloc->r_address);
+ return 0;
+ }
if(!reloc->r_extern)
{
}
#endif
}
- barf("\nunknown relocation %d",reloc->r_type);
- return 0;
+ else
+ {
+ barf("Can't handle Mach-O relocation entry (not scattered) "
+ "with this r_length tag: "
+ "object file %s; entry type %ld; "
+ "r_length tag %ld; address %#lx\n",
+ oc->fileName, reloc->r_type, reloc->r_length,
+ reloc->r_address);
+ return 0;
+ }
}
#endif
}
* Yuck.
*/
+extern void* symbolsWithoutUnderscore[];
+
static void machoInitSymbolsWithoutUnderscore()
{
- extern void* symbolsWithoutUnderscore[];
void **p = symbolsWithoutUnderscore;
__asm__ volatile(".globl _symbolsWithoutUnderscore\n.data\n_symbolsWithoutUnderscore:");
}
#endif
+#ifndef USE_MMAP
/*
* Figure out by how much to shift the entire Mach-O file in memory
* when loading so that its single segment ends up 16-byte-aligned
fread(&header, sizeof(header), 1, f);
rewind(f);
-#if x86_64_TARGET_ARCH || powerpc64_TARGET_ARCH
- if(header.magic != MH_MAGIC_64)
+#if x86_64_HOST_ARCH || powerpc64_HOST_ARCH
+ if(header.magic != MH_MAGIC_64) {
+ errorBelch("Bad magic. Expected: %08x, got: %08x.\n",
+ MH_MAGIC_64, header->magic);
return 0;
+ }
#else
- if(header.magic != MH_MAGIC)
+ if(header.magic != MH_MAGIC) {
+ errorBelch("Bad magic. Expected: %08x, got: %08x.\n",
+ MH_MAGIC, header->magic);
return 0;
+ }
#endif
misalignment = (header.sizeofcmds + sizeof(header))
return misalignment ? (16 - misalignment) : 0;
}
-
#endif
+#endif