/* -----------------------------------------------------------------------------
- * $Id: Linker.c,v 1.100 2002/07/18 06:05:29 sof Exp $
+ * $Id: Linker.c,v 1.109 2002/12/27 10:32:59 panne Exp $
*
* (c) The GHC Team, 2000, 2001
*
#include <sys/stat.h>
#endif
-#ifdef HAVE_DLFCN_H
+#if defined(HAVE_FRAMEWORK_HASKELLSUPPORT)
+#include <HaskellSupport/dlfcn.h>
+#elif defined(HAVE_DLFCN_H)
#include <dlfcn.h>
#endif
# include <windows.h>
# include <math.h>
#elif defined(darwin_TARGET_OS)
+# include <mach-o/ppc/reloc.h>
# define OBJFORMAT_MACHO
# include <mach-o/loader.h>
# include <mach-o/nlist.h>
#endif
/* Hash table mapping symbol names to Symbol */
-/*Str*/HashTable *symhash;
+static /*Str*/HashTable *symhash;
+
+/* List of currently loaded objects */
+ObjectCode *objects = NULL; /* initially empty */
#if defined(OBJFORMAT_ELF)
static int ocVerifyImage_ELF ( ObjectCode* oc );
Maybe_Stable_Names \
Sym(StgReturn) \
Sym(init_stack) \
- SymX(__stg_chk_0) \
- SymX(__stg_chk_1) \
- SymX(stg_chk_2) \
- SymX(stg_chk_3) \
- SymX(stg_chk_4) \
- SymX(stg_chk_5) \
- SymX(stg_chk_6) \
- SymX(stg_chk_7) \
- SymX(stg_chk_8) \
- Sym(stg_enterStackTop) \
- SymX(stg_gc_d1) \
- SymX(stg_gc_l1) \
+ SymX(stg_enter_info) \
+ SymX(stg_enter_ret) \
+ SymX(stg_gc_void_info) \
SymX(__stg_gc_enter_1) \
- SymX(stg_gc_enter_2) \
- SymX(stg_gc_enter_3) \
- SymX(stg_gc_enter_4) \
- SymX(stg_gc_enter_5) \
- SymX(stg_gc_enter_6) \
- SymX(stg_gc_enter_7) \
- SymX(stg_gc_enter_8) \
- SymX(stg_gc_f1) \
SymX(stg_gc_noregs) \
- SymX(stg_gc_seq_1) \
- SymX(stg_gc_unbx_r1) \
+ SymX(stg_gc_unpt_r1_info) \
SymX(stg_gc_unpt_r1) \
- SymX(stg_gc_ut_0_1) \
- SymX(stg_gc_ut_1_0) \
- SymX(stg_gen_chk) \
+ SymX(stg_gc_unbx_r1_info) \
+ SymX(stg_gc_unbx_r1) \
+ SymX(stg_gc_f1_info) \
+ SymX(stg_gc_f1) \
+ SymX(stg_gc_d1_info) \
+ SymX(stg_gc_d1) \
+ SymX(stg_gc_l1_info) \
+ 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) \
+ SymX(stg_gc_ut) \
+ SymX(stg_gen_yield) \
+ SymX(stg_yield_noregs) \
SymX(stg_yield_to_interpreter) \
+ SymX(stg_gen_block) \
+ SymX(stg_block_noregs) \
+ SymX(stg_block_1) \
+ SymX(stg_block_takemvar) \
+ SymX(stg_block_putmvar) \
+ SymX(stg_seq_frame_info) \
SymX(ErrorHdrHook) \
MAIN_CAP_SYM \
SymX(MallocFailHook) \
SymX(newArrayzh_fast) \
SymX(newBCOzh_fast) \
SymX(newByteArrayzh_fast) \
- SymX(newCAF) \
+ SymX_redirect(newCAF, newDynCAF) \
SymX(newMVarzh_fast) \
SymX(newMutVarzh_fast) \
+ SymX(atomicModifyMutVarzh_fast) \
SymX(newPinnedByteArrayzh_fast) \
SymX(orIntegerzh_fast) \
SymX(performGC) \
SymX(rts_evalIO) \
SymX(rts_evalLazyIO) \
SymX(rts_eval_) \
- SymX(rts_getAddr) \
SymX(rts_getBool) \
SymX(rts_getChar) \
SymX(rts_getDouble) \
SymX(rts_getThreadId) \
SymX(rts_getWord) \
SymX(rts_getWord32) \
- SymX(rts_mkAddr) \
SymX(rts_mkBool) \
SymX(rts_mkChar) \
SymX(rts_mkDouble) \
SymX(stg_INTLIKE_closure) \
SymX(stg_MUT_ARR_PTRS_FROZEN_info) \
SymX(stg_WEAK_info) \
+ SymX(stg_ap_v_info) \
+ SymX(stg_ap_f_info) \
+ SymX(stg_ap_d_info) \
+ SymX(stg_ap_l_info) \
+ SymX(stg_ap_n_info) \
+ SymX(stg_ap_p_info) \
+ SymX(stg_ap_pv_info) \
+ SymX(stg_ap_pp_info) \
+ SymX(stg_ap_ppv_info) \
+ SymX(stg_ap_ppp_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) \
SymX(stg_sel_7_upd_info) \
SymX(stg_sel_8_upd_info) \
SymX(stg_sel_9_upd_info) \
- SymX(stg_seq_frame_info) \
SymX(stg_upd_frame_info) \
- SymX(__stg_update_PAP) \
SymX(suspendThread) \
SymX(takeMVarzh_fast) \
SymX(timesIntegerzh_fast) \
#define RTS_EXTRA_SYMBOLS \
Sym(__divsf3)
#elif defined(powerpc_TARGET_ARCH)
-#define RTS_EXTRA_SYMBOLS \
+#define RTS_EXTRA_SYMBOLS \
Sym(__divdi3) \
Sym(__udivdi3) \
Sym(__moddi3) \
- Sym(__umoddi3) \
- Sym(__ashldi3) \
- Sym(__ashrdi3) \
- Sym(__lshrdi3) \
- SymX(__eprintf)
+ Sym(__umoddi3) \
+ Sym(__ashldi3) \
+ Sym(__ashrdi3) \
+ Sym(__lshrdi3) \
+ Sym(__eprintf)
#else
#define RTS_EXTRA_SYMBOLS /* nothing */
#endif
/* entirely bogus claims about types of these symbols */
#define Sym(vvv) extern void (vvv);
#define SymX(vvv) /**/
+#define SymX_redirect(vvv,xxx) /**/
RTS_SYMBOLS
RTS_LONG_LONG_SYMS
RTS_EXTRA_SYMBOLS
RTS_CYGWIN_ONLY_SYMBOLS
#undef Sym
#undef SymX
+#undef SymX_redirect
#ifdef LEADING_UNDERSCORE
#define MAYBE_LEADING_UNDERSCORE_STR(s) ("_" s)
(void*)(&(vvv)) },
#define SymX(vvv) Sym(vvv)
+// SymX_redirect allows us to redirect references to one symbol to
+// another symbol. See newCAF/newDynCAF for an example.
+#define SymX_redirect(vvv,xxx) \
+ { MAYBE_LEADING_UNDERSCORE_STR(#vvv), \
+ (void*)(&(xxx)) },
+
static RtsSymbolVal rtsSyms[] = {
RTS_SYMBOLS
RTS_LONG_LONG_SYMS
/* -----------------------------------------------------------------------------
* initialize the object linker
*/
+
+
+static int linker_init_done = 0 ;
+
#if defined(OBJFORMAT_ELF) || defined(OBJFORMAT_MACHO)
static void *dl_prog_handle;
#endif
{
RtsSymbolVal *sym;
+ /* Make initLinker idempotent, so we can call it
+ before evey relevant operation; that means we
+ don't need to initialise the linker separately */
+ if (linker_init_done == 1) { return; } else {
+ linker_init_done = 1;
+ }
+
symhash = allocStrHashTable();
/* populate the symbol table with stuff from the RTS */
}
/* -----------------------------------------------------------------------------
+ * Loading DLL or .so dynamic libraries
+ * -----------------------------------------------------------------------------
+ *
* Add a DLL from which symbols may be found. In the ELF case, just
* do RTLD_GLOBAL-style add, so no further messing around needs to
* happen in order that symbols in the loaded .so are findable --
*
* In the PEi386 case, open the DLLs and put handles to them in a
* linked list. When looking for a symbol, try all handles in the
- * list.
+ * list. This means that we need to load even DLLs that are guaranteed
+ * to be in the ghc.exe image already, just so we can get a handle
+ * 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)
static OpenedDLL* opened_dlls = NULL;
#endif
-
-
char *
addDLL( char *dll_name )
{
# if defined(OBJFORMAT_ELF) || defined(OBJFORMAT_MACHO)
+ /* ------------------- ELF DLL loader ------------------- */
void *hdl;
char *errmsg;
+ initLinker();
+
hdl= dlopen(dll_name, RTLD_NOW | RTLD_GLOBAL);
if (hdl == NULL) {
/* dlopen failed; return a ptr to the error msg. */
/*NOTREACHED*/
# elif defined(OBJFORMAT_PEi386)
+ /* ------------------- Win32 DLL loader ------------------- */
- /* Add this DLL to the list of DLLs in which to search for symbols.
- The path argument is ignored. */
char* buf;
OpenedDLL* o_dll;
HINSTANCE instance;
- /* fprintf(stderr, "\naddDLL; path=`%s', dll_name = `%s'\n", path, dll_name); */
+ initLinker();
+
+ /* fprintf(stderr, "\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) {
return NULL;
}
+ /* The file name has no suffix (yet) so that we can try
+ both foo.dll and foo.drv
+
+ The documentation for LoadLibrary says:
+ If no file name extension is specified in the lpFileName
+ parameter, the default library extension .dll is
+ appended. However, the file name string can include a trailing
+ point character (.) to indicate that the module name has no
+ extension. */
+
buf = stgMallocBytes(strlen(dll_name) + 10, "addDLL");
sprintf(buf, "%s.DLL", dll_name);
instance = LoadLibrary(buf);
if (instance == NULL) {
- sprintf(buf, "%s.DRV", dll_name); // KAA: allow loading of drivers (like winspool.drv)
+ sprintf(buf, "%s.DRV", dll_name); // KAA: allow loading of drivers (like winspool.drv)
instance = LoadLibrary(buf);
if (instance == NULL) {
free(buf);
}
free(buf);
+ /* Add this DLL to the list of DLLs in which to search for symbols. */
o_dll = stgMallocBytes( sizeof(OpenedDLL), "addDLL" );
o_dll->name = stgMallocBytes(1+strlen(dll_name), "addDLL");
strcpy(o_dll->name, dll_name);
lookupSymbol( char *lbl )
{
void *val;
+ initLinker() ;
ASSERT(symhash != NULL);
val = lookupStrHashTable(symhash, lbl);
lookupLocalSymbol( ObjectCode* oc, char *lbl )
{
void *val;
+ initLinker() ;
val = lookupStrHashTable(oc->lochash, lbl);
if (val == NULL) {
char* a;
const int DELTA = 64;
ObjectCode* oc;
+
+ initLinker();
+
for (oc = objects; oc; oc = oc->next) {
for (i = 0; i < oc->n_symbols; i++) {
sym = oc->symbols[i];
if (sym == NULL) continue;
- /* fprintf(stderr, "enquire %p %p\n", sym, oc->lochash); */
+ // fprintf(stderr, "enquire %p %p\n", sym, oc->lochash);
a = NULL;
- if (oc->lochash != NULL)
+ if (oc->lochash != NULL) {
a = lookupStrHashTable(oc->lochash, sym);
- if (a == NULL)
+ }
+ if (a == NULL) {
a = lookupStrHashTable(symhash, sym);
+ }
if (a == NULL) {
- /* fprintf(stderr, "ghci_enquire: can't find %s\n", sym); */
+ // fprintf(stderr, "ghci_enquire: can't find %s\n", sym);
}
else if (addr-DELTA <= a && a <= addr+DELTA) {
fprintf(stderr, "%p + %3d == `%s'\n", addr, a - addr, sym);
FILE *f;
#endif
+ initLinker();
+
/* fprintf(stderr, "loadObj %s\n", path ); */
/* Check that we haven't already loaded this object. Don't give up
ObjectCode *oc;
int r;
+ initLinker();
+
for (oc = objects; oc; oc = oc->next) {
if (oc->status != OBJECT_RESOLVED) {
# if defined(OBJFORMAT_ELF)
ASSERT(symhash != NULL);
ASSERT(objects != NULL);
+ initLinker();
+
prev = NULL;
for (oc = objects; oc; prev = oc, oc = oc->next) {
if (!strcmp(oc->fileName,path)) {
if ((void*)S != NULL) goto foundit;
(void*)S = lookupSymbol( symbol );
if ((void*)S != NULL) goto foundit;
- belch("%s: unknown symbol `%s'", oc->fileName, symbol);
+ /* Newline first because the interactive linker has printed "linking..." */
+ belch("\n%s: unknown symbol `%s'", oc->fileName, symbol);
return 0;
foundit:
}
if(reloc->r_pcrel && !reloc->r_extern)
continue;
- if(!reloc->r_pcrel
- && reloc->r_length == 2
- && reloc->r_type == GENERIC_RELOC_VANILLA)
+ if(!reloc->r_pcrel && reloc->r_length == 2)
{
- unsigned long* word = (unsigned long*) (image + sect->offset + reloc->r_address);
+ unsigned long word;
+
+ unsigned long* wordPtr = (unsigned long*) (image + sect->offset + reloc->r_address);
+ if(reloc->r_type == GENERIC_RELOC_VANILLA)
+ {
+ word = *wordPtr;
+ }
+ else if(reloc->r_type == PPC_RELOC_LO16)
+ {
+ word = ((unsigned short*) wordPtr)[1];
+ word |= ((unsigned long) relocs[i+1].r_address & 0xFFFF) << 16;
+ }
+ else if(reloc->r_type == PPC_RELOC_HI16)
+ {
+ word = ((unsigned short*) wordPtr)[1] << 16;
+ word |= ((unsigned long) relocs[i+1].r_address & 0xFFFF);
+ }
+ else if(reloc->r_type == PPC_RELOC_HA16)
+ {
+ word = ((unsigned short*) wordPtr)[1] << 16;
+ word += ((short)relocs[i+1].r_address & (short)0xFFFF);
+ }
+
if(!reloc->r_extern)
{
long delta =
- sections[reloc->r_symbolnum-1].addr
+ ((long) image);
- *word += delta;
+ 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);
+ word = (unsigned long) (lookupSymbol(nm));
+ ASSERT(word);
+ }
+
+ if(reloc->r_type == GENERIC_RELOC_VANILLA)
+ {
+ *wordPtr = word;
+ continue;
+ }
+ else if(reloc->r_type == PPC_RELOC_LO16)
+ {
+ ((unsigned short*) wordPtr)[1] = word & 0xFFFF;
+ i++; continue;
+ }
+ else if(reloc->r_type == PPC_RELOC_HI16)
+ {
+ ((unsigned short*) wordPtr)[1] = (word >> 16) & 0xFFFF;
+ i++; continue;
+ }
+ else if(reloc->r_type == PPC_RELOC_HA16)
+ {
+ ((unsigned short*) wordPtr)[1] = ((word >> 16) & 0xFFFF)
+ + ((word & (1<<15)) ? 1 : 0);
+ i++; continue;
}
continue;
}