Commit 90538d86 authored by Tamar Christina's avatar Tamar Christina Committed by Ben Gamari

Change runtime linker to perform lazy loading of symbols/sections

The Runtime Linker is currently eagerly loading all object files on all
platforms which do not use the system linker for `GHCi`.

The problem with this approach is that it requires all symbols to be
found.  Even those of functions never used/called. This makes the number
of libraries required to link things like `mingwex` quite high.

To work around this the `rts` was relying on a trick. It itself was
compiled with `MingW64-w`'s `GCC`. So it was already linked against
`mingwex`.  As such, it re-exported the symbols from itself.

While this worked it made it impossible to link against `mingwex` in
user libraries. And with this means no `C99` code could ever run in
`GHCi` on Windows without having the required symbols re-exported from
the rts.

Consequently this rules out a large number of packages on Windows.
SDL2, HMatrix etc.

After talking with @rwbarton I have taken the approach of loading entire
object files when a symbol is needed instead of doing the dependency
tracking on a per symbol basis. This is a lot less fragile and a lot
less complicated to implement.

The changes come down to the following steps:

1) modify the linker to and introduce a new state for ObjectCode:
   `Needed`.  A Needed object is one that is required for the linking to
   succeed.  The initial set consists of all Object files passed as
   arguments to the link.

2) Change `ObjectCode`'s to be indexed but not initialized or resolved.
   This means we know where we would load the symbols,
   but haven't actually done so.

3) Mark any `ObjectCode` belonging to `.o` passed as argument
   as required: ObjectState `NEEDED`.

4) During `Resolve` object calls, mark all `ObjectCode`
   containing the required symbols as `NEEDED`

5) During `lookupSymbol` lookups, (which is called from `linkExpr`
   and `linkDecl` in `GHCI.hs`) is the symbol is in a not-yet-loaded
   `ObjectCode` then load the `ObjectCode` on demand and return the
   address of the symbol. Otherwise produce an unresolved symbols error
   as expected.

6) On `unloadObj` we then change the state of the object and remove
   it's symbols from the `reqSymHash` table so it can be reloaded.

This change affects all platforms and OSes which use the runtime linker.
It seems there are no real perf tests for `GHCi`, but performance
shouldn't be impacted much. We gain a lot of time not loading all `obj`
files, and we lose some time in `lookupSymbol` when we're finding
sections that have to be loaded. The actual finding itself is O(1)
(Assuming the hashtnl is perfect)

It also consumes slighly more memory as instead of storing just the
address of a symbol I also store some other information, like if the
symbol is weak or not.

This change will break any packages relying on renamed POSIX functions
that were re-named and re-exported by the rts. Any packages following
the proper naming for functions as found on MSDN will work fine.

Test Plan: ./validate on all platforms which use the Runtime linker.

Reviewers: thomie, rwbarton, simonmar, erikd, bgamari, austin, hvr

Reviewed By: erikd

Subscribers: kgardas, gridaphobe, RyanGlScott, simonmar,
             rwbarton, #ghc_windows_task_force

Differential Revision: https://phabricator.haskell.org/D1805

GHC Trac Issues: #11223
parent 8987ce06
......@@ -934,9 +934,24 @@ runLink dflags args = do
let (p,args0) = pgm_l dflags
args1 = map Option (getOpts dflags opt_l)
args2 = args0 ++ linkargs ++ args1 ++ args
mb_env <- getGccEnv args2
runSomethingResponseFile dflags ld_filter "Linker" p args2 mb_env
args3 = argFixup args2 []
mb_env <- getGccEnv args3
runSomethingResponseFile dflags ld_filter "Linker" p args3 mb_env
where
testLib lib = "-l" `isPrefixOf` lib || ".a" `isSuffixOf` lib
{- GHC is just blindly appending linker arguments from libraries and
the commandline together. This results in very problematic link orders
which will cause incorrect linking. Since we're changing the link
arguments anyway, let's just make sure libraries are last.
This functions moves libraries on the link all the way back
but keeps the order amongst them the same. -}
argFixup [] r = [] ++ r
argFixup (o@(Option opt):xs) r = if testLib opt
then argFixup xs (r ++ [o])
else o:argFixup xs r
argFixup (o@(FileOption _ opt):xs) r = if testLib opt
then argFixup xs (r ++ [o])
else o:argFixup xs r
ld_filter = case (platformOS (targetPlatform dflags)) of
OSSolaris2 -> sunos_ld_filter
_ -> id
......
......@@ -1001,9 +1001,6 @@ AC_COMPILE_IFELSE(
AC_DEFINE([CC_SUPPORTS_TLS],[0],[Define to 1 if __thread is supported])
])
AC_CHECK_FUNCS(__mingw_vfprintf)
dnl large address space support (see includes/rts/storage/MBlock.h)
dnl
dnl Darwin has vm_allocate/vm_protect
......
......@@ -72,6 +72,9 @@ The highlights, since the 7.10 branch, are:
- Support for Windows XP and earlier has been dropped.
- GHC RTS No longer re-exports POSIX functions under their deprecated
names on Windows.
Full details
------------
......@@ -458,6 +461,12 @@ Runtime system
choose to use at most ⟨x⟩ capabilities, limited by the number of processors
as :rts-flag:`-N` is.
- The runtime linker is no longer greedy and will load only the needed objects
from archives. This means particularly on Windows packages requiring e.g. C99
support will now function properly. As part of this the RTS on Windows
no longer re-exports deprecated posix functions under the undeprecated names
(see :ghc-ticket:`11223`).
Build system
~~~~~~~~~~~~
......
......@@ -352,49 +352,115 @@ type CFilePath = CString
type CFilePath = CWString
#endif
foreign import ccall unsafe "HsBase.h access"
foreign import ccall unsafe "HsBase.h __hscore_open"
c_open :: CFilePath -> CInt -> CMode -> IO CInt
foreign import ccall safe "HsBase.h __hscore_open"
c_safe_open :: CFilePath -> CInt -> CMode -> IO CInt
foreign import ccall unsafe "HsBase.h __hscore_fstat"
c_fstat :: CInt -> Ptr CStat -> IO CInt
foreign import ccall unsafe "HsBase.h __hscore_lstat"
lstat :: CFilePath -> Ptr CStat -> IO CInt
{- Note: Win32 POSIX functions
Functions that are not part of the POSIX standards were
at some point deprecated by Microsoft. This deprecation
was performed by renaming the functions according to the
C++ ABI Section 17.6.4.3.2b. This was done to free up the
namespace of normal Windows programs since Windows isn't
POSIX compliant anyway.
These were working before since the RTS was re-exporting
these symbols under the undeprecated names. This is no longer
being done. See #11223
See https://msdn.microsoft.com/en-us/library/ms235384.aspx
for more.
-}
#if defined(mingw32_HOST_OS)
foreign import ccall unsafe "io.h _lseeki64"
c_lseek :: CInt -> Int64 -> CInt -> IO Int64
foreign import ccall unsafe "HsBase.h _access"
c_access :: CString -> CInt -> IO CInt
foreign import ccall unsafe "HsBase.h chmod"
foreign import ccall unsafe "HsBase.h _chmod"
c_chmod :: CString -> CMode -> IO CInt
foreign import ccall unsafe "HsBase.h close"
foreign import ccall unsafe "HsBase.h _close"
c_close :: CInt -> IO CInt
foreign import ccall unsafe "HsBase.h creat"
foreign import ccall unsafe "HsBase.h _creat"
c_creat :: CString -> CMode -> IO CInt
foreign import ccall unsafe "HsBase.h dup"
foreign import ccall unsafe "HsBase.h _dup"
c_dup :: CInt -> IO CInt
foreign import ccall unsafe "HsBase.h dup2"
foreign import ccall unsafe "HsBase.h _dup2"
c_dup2 :: CInt -> CInt -> IO CInt
foreign import ccall unsafe "HsBase.h __hscore_fstat"
c_fstat :: CInt -> Ptr CStat -> IO CInt
foreign import ccall unsafe "HsBase.h isatty"
foreign import ccall unsafe "HsBase.h _isatty"
c_isatty :: CInt -> IO CInt
#if defined(mingw32_HOST_OS)
foreign import ccall unsafe "io.h _lseeki64"
c_lseek :: CInt -> Int64 -> CInt -> IO Int64
-- See Note: CSsize
foreign import capi unsafe "HsBase.h _read"
c_read :: CInt -> Ptr Word8 -> CSize -> IO CSsize
-- See Note: CSsize
foreign import capi safe "HsBase.h _read"
c_safe_read :: CInt -> Ptr Word8 -> CSize -> IO CSsize
foreign import ccall unsafe "HsBase.h _umask"
c_umask :: CMode -> IO CMode
-- See Note: CSsize
foreign import capi unsafe "HsBase.h _write"
c_write :: CInt -> Ptr Word8 -> CSize -> IO CSsize
-- See Note: CSsize
foreign import capi safe "HsBase.h _write"
c_safe_write :: CInt -> Ptr Word8 -> CSize -> IO CSsize
foreign import ccall unsafe "HsBase.h _unlink"
c_unlink :: CString -> IO CInt
foreign import ccall unsafe "HsBase.h _pipe"
c_pipe :: Ptr CInt -> IO CInt
foreign import capi unsafe "HsBase.h _utime"
c_utime :: CString -> Ptr CUtimbuf -> IO CInt
foreign import ccall unsafe "HsBase.h _getpid"
c_getpid :: IO CPid
#else
-- We use CAPI as on some OSs (eg. Linux) this is wrapped by a macro
-- which redirects to the 64-bit-off_t versions when large file
-- support is enabled.
foreign import capi unsafe "unistd.h lseek"
c_lseek :: CInt -> COff -> CInt -> IO COff
#endif
foreign import ccall unsafe "HsBase.h __hscore_lstat"
lstat :: CFilePath -> Ptr CStat -> IO CInt
foreign import ccall unsafe "HsBase.h access"
c_access :: CString -> CInt -> IO CInt
foreign import ccall unsafe "HsBase.h __hscore_open"
c_open :: CFilePath -> CInt -> CMode -> IO CInt
foreign import ccall unsafe "HsBase.h chmod"
c_chmod :: CString -> CMode -> IO CInt
foreign import ccall safe "HsBase.h __hscore_open"
c_safe_open :: CFilePath -> CInt -> CMode -> IO CInt
foreign import ccall unsafe "HsBase.h close"
c_close :: CInt -> IO CInt
foreign import ccall unsafe "HsBase.h creat"
c_creat :: CString -> CMode -> IO CInt
foreign import ccall unsafe "HsBase.h dup"
c_dup :: CInt -> IO CInt
foreign import ccall unsafe "HsBase.h dup2"
c_dup2 :: CInt -> CInt -> IO CInt
foreign import ccall unsafe "HsBase.h isatty"
c_isatty :: CInt -> IO CInt
-- See Note: CSsize
foreign import capi unsafe "HsBase.h read"
......@@ -404,9 +470,6 @@ foreign import capi unsafe "HsBase.h read"
foreign import capi safe "HsBase.h read"
c_safe_read :: CInt -> Ptr Word8 -> CSize -> IO CSsize
foreign import ccall unsafe "HsBase.h __hscore_stat"
c_stat :: CFilePath -> Ptr CStat -> IO CInt
foreign import ccall unsafe "HsBase.h umask"
c_umask :: CMode -> IO CMode
......@@ -418,14 +481,24 @@ foreign import capi unsafe "HsBase.h write"
foreign import capi safe "HsBase.h write"
c_safe_write :: CInt -> Ptr Word8 -> CSize -> IO CSsize
foreign import ccall unsafe "HsBase.h __hscore_ftruncate"
c_ftruncate :: CInt -> COff -> IO CInt
foreign import ccall unsafe "HsBase.h unlink"
c_unlink :: CString -> IO CInt
foreign import ccall unsafe "HsBase.h pipe"
c_pipe :: Ptr CInt -> IO CInt
foreign import capi unsafe "HsBase.h utime"
c_utime :: CString -> Ptr CUtimbuf -> IO CInt
foreign import ccall unsafe "HsBase.h getpid"
c_getpid :: IO CPid
#endif
foreign import ccall unsafe "HsBase.h __hscore_stat"
c_stat :: CFilePath -> Ptr CStat -> IO CInt
foreign import ccall unsafe "HsBase.h __hscore_ftruncate"
c_ftruncate :: CInt -> COff -> IO CInt
#if !defined(mingw32_HOST_OS)
foreign import capi unsafe "HsBase.h fcntl"
......@@ -447,9 +520,6 @@ foreign import ccall unsafe "HsBase.h link"
foreign import capi unsafe "HsBase.h mkfifo"
c_mkfifo :: CString -> CMode -> IO CInt
foreign import ccall unsafe "HsBase.h pipe"
c_pipe :: Ptr CInt -> IO CInt
foreign import capi unsafe "signal.h sigemptyset"
c_sigemptyset :: Ptr CSigset -> IO CInt
......@@ -467,9 +537,6 @@ foreign import capi unsafe "HsBase.h tcgetattr"
foreign import capi unsafe "HsBase.h tcsetattr"
c_tcsetattr :: CInt -> CInt -> Ptr CTermios -> IO CInt
foreign import capi unsafe "HsBase.h utime"
c_utime :: CString -> Ptr CUtimbuf -> IO CInt
foreign import ccall unsafe "HsBase.h waitpid"
c_waitpid :: CPid -> Ptr CInt -> CInt -> IO CPid
#endif
......
......@@ -336,7 +336,15 @@ Library
-- OS Specific
if os(windows)
extra-libraries: wsock32, user32, shell32
-- Windows requires some extra libraries for linking because the RTS
-- is no longer re-exporting them.
-- msvcrt: standard C library. The RTS will automatically include this,
-- but is added for completeness.
-- mingwex: provides C99 compatibility. libm is a stub on MingW.
-- mingw32: Unfortunately required because of a resource leak between
-- mingwex and mingw32. the __math_err symbol is defined in
-- mingw32 which is required by mingwex.
extra-libraries: wsock32, user32, shell32, msvcrt, mingw32, mingwex
exposed-modules:
GHC.IO.Encoding.CodePage.API
GHC.IO.Encoding.CodePage.Table
......
......@@ -299,7 +299,7 @@ INLINE int
__hscore_setmode( int fd, HsBool toBin )
{
#if defined(_WIN32)
return setmode(fd,(toBin == HS_BOOL_TRUE) ? _O_BINARY : _O_TEXT);
return _setmode(fd,(toBin == HS_BOOL_TRUE) ? _O_BINARY : _O_TEXT);
#else
return 0;
#endif
......
......@@ -53,6 +53,20 @@ Library
GHC.Tuple
GHC.Types
-- OS Specific
if os(windows)
-- Windows requires some extra libraries for linking because the RTS
-- is no longer re-exporting them (see #11223)
-- msvcrt: standard C library. The RTS will automatically include this,
-- but is added for completeness.
-- mingwex: provides C99 compatibility. libm is a stub on MingW.
-- mingw32: Unfortunately required because of a resource leak between
-- mingwex and mingw32. the __math_err symbol is defined in
-- mingw32 which is required by mingwex.
-- user32: provides access to apis to modify user components (UI etc)
-- on Windows. Required because of mingw32.
extra-libraries: user32, mingw32, mingwex
if flag(include-ghc-prim)
exposed-modules: GHC.Prim
......
......@@ -130,13 +130,85 @@
#include <sys/tls.h>
#endif
/* SymbolInfo tracks a symbol's address, the object code from which
it originated, and whether or not it's weak.
Refactoring idea: For the sake of memory efficiency it might be worthwhile
dropping the `weak` field, instead keeping a list of weak symbols in
ObjectCode. This is task #11816.
*/
typedef struct _RtsSymbolInfo {
void *value;
const ObjectCode *owner;
ObjectCode *owner;
HsBool weak;
} RtsSymbolInfo;
/* Hash table mapping symbol names to RtsSymbolInfo */
/* `symhash` is a Hash table mapping symbol names to RtsSymbolInfo.
This hashtable will contain information on all symbols
that we know of, however the .o they are in may not be loaded.
Until the ObjectCode the symbol belongs to is actually
loaded this symbol may be replaced. So do not rely on
addresses of unloaded symbols.
Note [runtime-linker-phases]
--------------------------------------
Broadly the behavior of the runtime linker can be
split into the following four phases:
- Indexing (e.g. ocVerifyImage and ocGetNames)
- Initialization (e.g. ocResolve and ocRunInit)
- Resolve (e.g. resolveObjs())
- Lookup (e.g. lookupSymbol)
This is to enable lazy loading of symbols. Eager loading is problematic
as it means that all symbols must be available, even those which we will
never use. This is especially painful of Windows, where the number of
libraries required to link things like mingwex grows to be quite high.
We proceed through these stages as follows,
* During Indexing we verify and open the ObjectCode and
perform a quick scan/indexing of the ObjectCode. All the work
required to actually load the ObjectCode is done.
All symbols from the ObjectCode is also inserted into
`symhash`, where possible duplicates are handled via the semantics
described in `ghciInsertSymbolTable`.
This phase will produce ObjectCode with status `OBJECT_LOADED` or `OBJECT_NEEDED`
depending on whether they are an archive members or not.
* During initialization we load ObjectCode, perform relocations, execute
static constructors etc. This phase may trigger other ObjectCodes to
be loaded because of the calls to lookupSymbol.
This phase will produce ObjectCode with status `OBJECT_NEEDED` if the
previous status was `OBJECT_LOADED`.
* During resolve we attempt to resolve all the symbols needed for the
initial link. This essentially means, that for any ObjectCode given
directly to the command-line we perform lookupSymbols on the required
symbols. lookupSymbols may trigger the loading of additional ObjectCode
if required.
This phase will produce ObjectCode with status `OBJECT_RESOLVED` if
the previous status was `OBJECT_NEEDED`.
* Lookup symbols is used to lookup any symbols required, both during initial
link and during statement and expression compilations in the REPL.
Declaration of e.g. an foreign import, will eventually call lookupSymbol
which will either fail (symbol unknown) or succeed (and possibly triggered a
load).
This phase may transition an ObjectCode from `OBJECT_LOADED` to `OBJECT_RESOLVED`
When a new scope is introduced (e.g. a new module imported) GHCi does a full re-link
by calling unloadObj and starting over.
When a new declaration or statement is performed ultimately lookupSymbol is called
without doing a re-link.
*/
static /*Str*/HashTable *symhash;
/* List of currently loaded objects */
......@@ -193,7 +265,7 @@ static pathchar* pathdup(pathchar *path)
ret = wcsdup(path);
#else
/* sigh, strdup() isn't a POSIX function, so do it the long way */
ret = stgMallocBytes( strlen(path)+1, "loadObj" );
ret = stgMallocBytes( strlen(path)+1, "pathdup" );
strcpy(ret, path);
#endif
return ret;
......@@ -215,6 +287,9 @@ static pathchar* mkPath(char* path)
#endif
}
/* Generic wrapper function to try and Resolve and RunInit oc files */
int ocTryLoad( ObjectCode* oc );
#if defined(OBJFORMAT_ELF)
static int ocVerifyImage_ELF ( ObjectCode* oc );
static int ocGetNames_ELF ( ObjectCode* oc );
......@@ -264,10 +339,21 @@ static void machoInitSymbolsWithoutUnderscore( void );
#endif
#if defined(OBJFORMAT_PEi386)
/* Add ld symbol for PE image base. */
#if defined(__GNUC__)
#define __ImageBase __MINGW_LSYMBOL(_image_base__)
#endif
/* Get the base of the module. */
/* This symbol is defined by ld. */
extern IMAGE_DOS_HEADER __ImageBase;
#define __image_base (void*)((HINSTANCE)&__ImageBase)
// MingW-w64 is missing these from the implementation. So we have to look them up
typedef DLL_DIRECTORY_COOKIE(WINAPI *LPAddDLLDirectory)(PCWSTR NewDirectory);
typedef WINBOOL(WINAPI *LPRemoveDLLDirectory)(DLL_DIRECTORY_COOKIE Cookie);
#endif
#endif /* OBJFORMAT_PEi386 */
static void freeProddableBlocks (ObjectCode *oc);
......@@ -405,12 +491,36 @@ static void *mmap_32bit_base = (void *)MMAP_32BIT_BASE_DEFAULT;
#define MAP_ANONYMOUS MAP_ANON
#endif
static void ghciRemoveSymbolTable(HashTable *table, const char *key,
ObjectCode *owner)
{
RtsSymbolInfo *pinfo = lookupStrHashTable(table, key);
if (!pinfo || owner != pinfo->owner) return;
removeStrHashTable(table, key, NULL);
stgFree(pinfo);
}
/* -----------------------------------------------------------------------------
* Insert symbols into hash tables, checking for duplicates.
*
* Returns: 0 on failure, nonzero on success
*/
/*
Note [weak-symbols-support]
-------------------------------------
While ghciInsertSymbolTable does implement extensive
logic for weak symbol support, weak symbols are not currently
fully supported by the RTS. This code is mostly here for COMDAT
support which uses the weak symbols support.
Linking weak symbols defined purely in C code with other C code
should also work, probably. Observing weak symbols in Haskell
won't.
Some test have been written for weak symbols but have been disabled
mostly because it's unsure how the weak symbols support should look.
See Trac #11223
*/
static int ghciInsertSymbolTable(
pathchar* obj_name,
HashTable *table,
......@@ -429,11 +539,24 @@ static int ghciInsertSymbolTable(
insertStrHashTable(table, key, pinfo);
return 1;
}
else if ((!pinfo->weak || pinfo->value) && weak)
else if (weak && data && pinfo->weak && !pinfo->value)
{
return 1; /* duplicate weak symbol, throw it away */
/* The existing symbol is weak with a zero value; replace it with the new symbol. */
pinfo->value = data;
pinfo->owner = owner;
return 1;
}
else if (weak)
{
return 1; /* weak symbol, because the symbol is weak, data = 0 and we
already know of another copy throw this one away.
or both weak symbols have a nonzero value. Keep the existing one.
This also preserves the semantics of linking against
the first symbol we find. */
}
else if (pinfo->weak) /* weak symbol is in the table */
else if (pinfo->weak && !weak) /* weak symbol is in the table */
{
/* override the weak definition with the non-weak one */
pinfo->value = data;
......@@ -441,6 +564,42 @@ static int ghciInsertSymbolTable(
pinfo->weak = HS_BOOL_FALSE;
return 1;
}
else if ( pinfo->owner
&& pinfo->owner->status != OBJECT_RESOLVED
&& pinfo->owner->status != OBJECT_NEEDED)
{
/* If the other symbol hasn't been loaded or will be loaded and we want to
explicitly load the new one, we can just swap it out and load the one
that has been requested. If not, just keep the first one encountered.
Because the `symHash' table consists symbols we've also not loaded but
found during the initial scan this is safe to do. If however the existing
symbol has been loaded then it means we have a duplicate.
This is essentially emulating the behavior of a linker wherein it will always
link in object files that are .o file arguments, but only take object files
from archives as needed. */
if (owner && (owner->status == OBJECT_NEEDED || owner->status == OBJECT_RESOLVED)) {
pinfo->value = data;
pinfo->owner = owner;
pinfo->weak = weak;
}
return 1;
}
else if (pinfo->owner == owner)
{
/* If it's the same symbol, ignore. This makes ghciInsertSymbolTable idempotent */
return 1;
}
else if (owner && owner->status == OBJECT_LOADED)
{
/* If the duplicate symbol is just in state OBJECT_LOADED it means we're in discovery of an
member. It's not a real duplicate yet. If the Oc Becomes OBJECT_NEEDED then ocTryLoad will
call this function again to trigger the duplicate error. */
return 1;
}
pathchar* archiveName = NULL;
debugBelch(
"GHC runtime linker: fatal error: I found a duplicate definition for symbol\n"
......@@ -469,8 +628,14 @@ static int ghciInsertSymbolTable(
return 0;
}
static HsBool ghciLookupSymbolTable(HashTable *table,
const char *key, void **result)
/* -----------------------------------------------------------------------------
* Looks up symbols into hash tables.
*
* Returns: 0 on failure and result is not set,
* nonzero on success and result set to nonzero pointer
*/
static HsBool ghciLookupSymbolInfo(HashTable *table,
const char *key, RtsSymbolInfo **result)
{
RtsSymbolInfo *pinfo = lookupStrHashTable(table, key);
if (!pinfo) {
......@@ -478,22 +643,14 @@ static HsBool ghciLookupSymbolTable(HashTable *table,
return HS_BOOL_FALSE;
}
if (pinfo->weak)
IF_DEBUG(linker, debugBelch("lookup: promoting %s\n", key));
IF_DEBUG(linker, debugBelch("lookupSymbolInfo: promoting %s\n", key));
/* Once it's looked up, it can no longer be overridden */
pinfo->weak = HS_BOOL_FALSE;
*result = pinfo->value;
*result = pinfo;
return HS_BOOL_TRUE;
}
static void ghciRemoveSymbolTable(HashTable *table, const char *key,
ObjectCode *owner)
{
RtsSymbolInfo *pinfo = lookupStrHashTable(table, key);
if (!pinfo || owner != pinfo->owner) return;
removeStrHashTable(table, key, NULL);
stgFree(pinfo);
}
/* -----------------------------------------------------------------------------
* initialize the object linker
*/
......@@ -573,6 +730,14 @@ initLinker_ (int retain_cafs)
barf("ghciInsertSymbolTable failed");
}
#if defined(OBJFORMAT_PEi386)
if (!ghciInsertSymbolTable(WSTR("(GHCi/Ld special symbols)"),
symhash, "__image_base__", __image_base, HS_BOOL_TRUE, NULL)) {
barf("ghciInsertSymbolTable failed");
}
#endif /* OBJFORMAT_PEi386 */
// Redirect newCAF to newRetainedCAF if retain_cafs is true.
if (! ghciInsertSymbolTable(WSTR("(GHCi built-in symbols)"), symhash,
MAYBE_LEADING_UNDERSCORE_STR("newCAF"),
......@@ -914,7 +1079,7 @@ addDLL( pathchar *dll_name )
buf = stgMallocBytes(bufsize * sizeof(wchar_t), "addDLL");
/* These are ordered by probability of success and order we'd like them */
const wchar_t *formats[] = { L"%s.DLL", L"%s.DRV", L"lib%s.DLL", L"%s" };
const wchar_t *formats[] = { L"%ls.DLL", L"%ls.DRV", L"lib%ls.DLL", L"%ls" };
const DWORD flags[] = { LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS, 0 };
int cFormat;
......@@ -1154,13 +1319,14 @@ HsInt insertSymbol(pathchar* obj_name, char* key, void* data)
*/
static void* lookupSymbol_ (char *lbl)
{
void *val;
IF_DEBUG(linker, debugBelch("lookupSymbol: looking up %s\n", lbl));
ASSERT(symhash != NULL);
RtsSymbolInfo *pinfo;
if (!ghciLookupSymbolTable(symhash, lbl, &val)) {
if (!ghciLookupSymbolInfo(symhash, lbl, &pinfo)) {
IF_DEBUG(linker, debugBelch("lookupSymbol: symbol not found\n"));
# if defined(OBJFORMAT_ELF)
return internal_dlsym(lbl);
# elif defined(OBJFORMAT_MACHO)
......@@ -1189,7 +1355,25 @@ static void* lookupSymbol_ (char *lbl)
return NULL;
# endif
} else {
void *val = pinfo->value;
IF_DEBUG(linker, debugBelch("lookupSymbol: value of %s is %p\n", lbl, val));
int r;
ObjectCode* oc = pinfo->owner;
/* Symbol can be found during linking, but hasn't been relocated. Do so now.
See Note [runtime-linker-phases] */
if (oc && oc->status == OBJECT_LOADED) {
oc->status = OBJECT_NEEDED;
IF_DEBUG(linker, debugBelch("lookupSymbol: on-demand loaded symbol '%s'\n", lbl));
r = ocTryLoad(oc);