X-Git-Url: http://git.megacz.com/?p=ghc-hetmet.git;a=blobdiff_plain;f=rts%2FLinker.c;h=77938013254aaea20adeecd7a74fc45324e924f6;hp=3b7324de7c35e8df46c47982f975349bd98f6bdc;hb=c004ec62b41aa2137b5b5e298ca562609b0de92e;hpb=4d7f33a5ea53c2bf5900785dc3946c13c04430c1 diff --git a/rts/Linker.c b/rts/Linker.c index 3b7324d..7793801 100644 --- a/rts/Linker.c +++ b/rts/Linker.c @@ -83,7 +83,9 @@ # include # include # include +#if !defined(HAVE_DLFCN_H) # include +#endif #if defined(powerpc_HOST_ARCH) # include #endif @@ -105,7 +107,7 @@ 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_HOST_ARCH) +#if defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH) static int ocAllocateSymbolExtras_ELF ( ObjectCode* oc ); #endif #elif defined(OBJFORMAT_PEi386) @@ -126,9 +128,30 @@ static void machoInitSymbolsWithoutUnderscore( void ); #endif #endif -#if defined(x86_64_HOST_ARCH) && defined(OBJFORMAT_ELF) -static void*x86_64_high_symbol( char *lbl, void *addr ); -#endif +/* on x86_64 we have a problem with relocating symbol references in + * code that was compiled without -fPIC. By default, the small memory + * model is used, which assumes that symbol references can fit in a + * 32-bit slot. The system dynamic linker makes this work for + * references to shared libraries by either (a) allocating a jump + * table slot for code references, or (b) moving the symbol at load + * time (and copying its contents, if necessary) for data references. + * + * We unfortunately can't tell whether symbol references are to code + * or data. So for now we assume they are code (the vast majority + * are), and allocate jump-table slots. Unfortunately this will + * SILENTLY generate crashing code for data references. This hack is + * enabled by X86_64_ELF_NONPIC_HACK. + * + * One workaround is to use shared Haskell libraries. This is + * coming. Another workaround is to keep the static libraries but + * compile them with -fPIC, because that will generate PIC references + * to data which can be relocated. The PIC code is still too green to + * do this systematically, though. + * + * See bug #781 + * See thread http://www.haskell.org/pipermail/cvs-ghc/2007-September/038458.html + */ +#define X86_64_ELF_NONPIC_HACK 1 /* ----------------------------------------------------------------------------- * Built-in symbols from the RTS @@ -151,6 +174,8 @@ typedef struct _RtsSymbolVal { #if !defined (mingw32_HOST_OS) #define RTS_POSIX_ONLY_SYMBOLS \ + Sym(lockFile) \ + Sym(unlockFile) \ SymX(signal_handlers) \ SymX(stg_sig_install) \ Sym(nocldstop) @@ -256,6 +281,12 @@ typedef struct _RtsSymbolVal { #define RTS_MINGW_EXTRA_SYMS #endif +#if HAVE_GETTIMEOFDAY +#define RTS_MINGW_GETTIMEOFDAY_SYM Sym(gettimeofday) +#else +#define RTS_MINGW_GETTIMEOFDAY_SYM /**/ +#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 \ @@ -339,6 +370,7 @@ typedef struct _RtsSymbolVal { Sym(readdir) \ Sym(rewinddir) \ RTS_MINGW_EXTRA_SYMS \ + RTS_MINGW_GETTIMEOFDAY_SYM \ Sym(closedir) #endif @@ -470,12 +502,12 @@ typedef struct _RtsSymbolVal { SymX(__encodeDouble) \ SymX(__encodeFloat) \ SymX(addDLL) \ - SymX(__gmpn_gcd_1) \ - SymX(__gmpz_cmp) \ - SymX(__gmpz_cmp_si) \ - SymX(__gmpz_cmp_ui) \ - SymX(__gmpz_get_si) \ - SymX(__gmpz_get_ui) \ + SymExtern(__gmpn_gcd_1) \ + SymExtern(__gmpz_cmp) \ + SymExtern(__gmpz_cmp_si) \ + SymExtern(__gmpz_cmp_ui) \ + SymExtern(__gmpz_get_si) \ + SymExtern(__gmpz_get_ui) \ SymX(__int_encodeDouble) \ SymX(__int_encodeFloat) \ SymX(andIntegerzh_fast) \ @@ -516,6 +548,7 @@ typedef struct _RtsSymbolVal { SymX(genSymZh) \ SymX(genericRaise) \ SymX(getProgArgv) \ + SymX(getFullProgArgv) \ SymX(getStablePtr) \ SymX(hs_init) \ SymX(hs_exit) \ @@ -524,6 +557,7 @@ typedef struct _RtsSymbolVal { SymX(hs_perform_gc) \ SymX(hs_free_stable_ptr) \ SymX(hs_free_fun_ptr) \ + SymX(hs_hpc_rootModule) \ SymX(initLinker) \ SymX(unpackClosurezh_fast) \ SymX(getApStackValzh_fast) \ @@ -590,32 +624,38 @@ typedef struct _RtsSymbolVal { SymX(rts_getDouble) \ SymX(rts_getFloat) \ SymX(rts_getInt) \ + SymX(rts_getInt8) \ + SymX(rts_getInt16) \ SymX(rts_getInt32) \ + SymX(rts_getInt64) \ SymX(rts_getPtr) \ SymX(rts_getFunPtr) \ SymX(rts_getStablePtr) \ SymX(rts_getThreadId) \ SymX(rts_getWord) \ + SymX(rts_getWord8) \ + SymX(rts_getWord16) \ SymX(rts_getWord32) \ + SymX(rts_getWord64) \ SymX(rts_lock) \ SymX(rts_mkBool) \ SymX(rts_mkChar) \ SymX(rts_mkDouble) \ SymX(rts_mkFloat) \ SymX(rts_mkInt) \ + SymX(rts_mkInt8) \ SymX(rts_mkInt16) \ SymX(rts_mkInt32) \ SymX(rts_mkInt64) \ - SymX(rts_mkInt8) \ SymX(rts_mkPtr) \ SymX(rts_mkFunPtr) \ SymX(rts_mkStablePtr) \ SymX(rts_mkString) \ SymX(rts_mkWord) \ + SymX(rts_mkWord8) \ SymX(rts_mkWord16) \ SymX(rts_mkWord32) \ SymX(rts_mkWord64) \ - SymX(rts_mkWord8) \ SymX(rts_unlock) \ SymX(rtsSupportsBoundThreads) \ SymX(__hscore_get_saved_termios) \ @@ -629,7 +669,8 @@ typedef struct _RtsSymbolVal { SymX(stg_CAF_BLACKHOLE_info) \ SymX(awakenBlockedQueue) \ SymX(stg_CHARLIKE_closure) \ - SymX(stg_EMPTY_MVAR_info) \ + SymX(stg_MVAR_CLEAN_info) \ + SymX(stg_MVAR_DIRTY_info) \ SymX(stg_IND_STATIC_info) \ SymX(stg_INTLIKE_closure) \ SymX(stg_MUT_ARR_PTRS_DIRTY_info) \ @@ -710,8 +751,11 @@ typedef struct _RtsSymbolVal { SymX(getAllocations) \ SymX(revertCAFs) \ SymX(RtsFlags) \ - Sym(breakPointIOAction) \ - Sym(rts_setStepFlag) \ + SymX(rts_breakpoint_io_action) \ + SymX(rts_stop_next_breakpoint) \ + SymX(rts_stop_on_exception) \ + SymX(stopTimer) \ + SymX(n_capabilities) \ RTS_USER_SIGNALS_SYMBOLS #ifdef SUPPORT_LONG_LONGS @@ -757,6 +801,11 @@ typedef struct _RtsSymbolVal { /* entirely bogus claims about types of these symbols */ #define Sym(vvv) extern void vvv(void); +#if defined(__PIC__) && defined(mingw32_TARGET_OS) +#define SymExtern(vvv) extern void _imp__ ## vvv (void); +#else +#define SymExtern(vvv) SymX(vvv) +#endif #define SymX(vvv) /**/ #define SymX_redirect(vvv,xxx) /**/ RTS_SYMBOLS @@ -770,6 +819,7 @@ RTS_LIBGCC_SYMBOLS #undef Sym #undef SymX #undef SymX_redirect +#undef SymExtern #ifdef LEADING_UNDERSCORE #define MAYBE_LEADING_UNDERSCORE_STR(s) ("_" s) @@ -780,6 +830,8 @@ RTS_LIBGCC_SYMBOLS #define Sym(vvv) { MAYBE_LEADING_UNDERSCORE_STR(#vvv), \ (void*)(&(vvv)) }, #define SymX(vvv) Sym(vvv) +#define SymExtern(vvv) { MAYBE_LEADING_UNDERSCORE_STR(#vvv), \ + (void*)DLL_IMPORT_DATA_REF(vvv) }, // SymX_redirect allows us to redirect references to one symbol to // another symbol. See newCAF/newDynCAF for an example. @@ -919,13 +971,13 @@ typedef static OpenedDLL* opened_dlls = NULL; #endif -char * +const char * addDLL( char *dll_name ) { # if defined(OBJFORMAT_ELF) || defined(OBJFORMAT_MACHO) /* ------------------- ELF DLL loader ------------------- */ void *hdl; - char *errmsg; + const char *errmsg; initLinker(); @@ -1030,26 +1082,27 @@ lookupSymbol( char *lbl ) if (val == NULL) { # if defined(OBJFORMAT_ELF) -# if defined(x86_64_HOST_ARCH) - val = dlsym(dl_prog_handle, lbl); - if (val >= (void *)0x80000000) { - void *new_val; - new_val = x86_64_high_symbol(lbl, val); - IF_DEBUG(linker,debugBelch("lookupSymbol: relocating out of range symbol: %s = %p, now %p\n", lbl, val, new_val)); - return new_val; - } else { - return val; - } -# else return dlsym(dl_prog_handle, lbl); -# endif # elif defined(OBJFORMAT_MACHO) +# if HAVE_DLFCN_H + /* On OS X 10.3 and later, we use dlsym instead of the old legacy + interface. + + HACK: On OS X, global symbols are prefixed with an underscore. + However, dlsym wants us to omit the leading underscore from the + symbol name. For now, we simply strip it off here (and ONLY + here). + */ + ASSERT(lbl[0] == '_'); + return dlsym(dl_prog_handle, lbl+1); +# else if(NSIsSymbolNameDefined(lbl)) { NSSymbol symbol = NSLookupAndBindSymbol(lbl); return NSAddressOfSymbol(symbol); } else { return NULL; } +# endif /* HAVE_DLFCN_H */ # elif defined(OBJFORMAT_PEi386) OpenedDLL* o_dll; void* sym; @@ -1248,13 +1301,20 @@ loadObj( char *path ) /* Link objects into the lower 2Gb on x86_64. GHC assumes the * small memory model on this architecture (see gcc docs, * -mcmodel=small). + * + * MAP_32BIT not available on OpenBSD/amd64 */ -#ifdef x86_64_HOST_ARCH +#if defined(x86_64_HOST_ARCH) && defined(MAP_32BIT) #define EXTRA_MAP_FLAGS MAP_32BIT #else #define EXTRA_MAP_FLAGS 0 #endif + /* MAP_ANONYMOUS is MAP_ANON on some systems, e.g. OpenBSD */ +#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) +#define MAP_ANONYMOUS MAP_ANON +#endif + oc->image = mmap(map_addr, n, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|EXTRA_MAP_FLAGS, fd, 0); if (oc->image == MAP_FAILED) @@ -1301,7 +1361,7 @@ loadObj( char *path ) # if defined(OBJFORMAT_MACHO) && (defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH)) r = ocAllocateSymbolExtras_MachO ( oc ); if (!r) { return r; } -# elif defined(OBJFORMAT_ELF) && defined(powerpc_HOST_ARCH) +# elif defined(OBJFORMAT_ELF) && (defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH)) r = ocAllocateSymbolExtras_ELF ( oc ); if (!r) { return r; } #endif @@ -1483,8 +1543,7 @@ static void addSection ( ObjectCode* oc, SectionKind kind, * them right next to the object code itself. */ -#if defined(powerpc_HOST_ARCH) || (defined(x86_64_HOST_ARCH) \ - && defined(darwin_TARGET_OS)) +#if defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH) /* ocAllocateSymbolExtras @@ -1511,10 +1570,12 @@ static int ocAllocateSymbolExtras( ObjectCode* oc, int count, int first ) int pagesize, n, m; #endif int aligned; +#ifndef USE_MMAP int misalignment = 0; -#if darwin_HOST_OS +#ifdef darwin_HOST_OS misalignment = oc->misalignment; #endif +#endif if( count > 0 ) { @@ -2517,15 +2578,20 @@ ocResolve_PEi386 ( ObjectCode* oc ) #endif #if !defined(openbsd_HOST_OS) -#include +# include #else /* openbsd elf has things in different places, with diff names */ -#include -#include -#define R_386_32 RELOC_32 -#define R_386_PC32 RELOC_PC32 +# include +# include +# define R_386_32 RELOC_32 +# define R_386_PC32 RELOC_PC32 #endif +/* If elf.h doesn't define it */ +# ifndef R_X86_64_PC64 +# define R_X86_64_PC64 24 +# endif + /* * Define a set of types which can be used for both ELF32 and ELF64 */ @@ -2690,64 +2756,6 @@ PLTSize(void) #endif -#if x86_64_HOST_ARCH -// On x86_64, 32-bit relocations are often used, which requires that -// we can resolve a symbol to a 32-bit offset. However, shared -// libraries are placed outside the 2Gb area, which leaves us with a -// problem when we need to give a 32-bit offset to a symbol in a -// shared library. -// -// For a function symbol, we can allocate a bounce sequence inside the -// 2Gb area and resolve the symbol to this. The bounce sequence is -// simply a long jump instruction to the real location of the symbol. -// -// For data references, we're screwed. -// -typedef struct { - unsigned char jmp[8]; /* 6 byte instruction: jmpq *0x00000002(%rip) */ - void *addr; -} x86_64_bounce; - -#define X86_64_BB_SIZE 1024 - -static x86_64_bounce *x86_64_bounce_buffer = NULL; -static nat x86_64_bb_next_off; - -static void* -x86_64_high_symbol( char *lbl, void *addr ) -{ - x86_64_bounce *bounce; - - if ( x86_64_bounce_buffer == NULL || - x86_64_bb_next_off >= X86_64_BB_SIZE ) { - x86_64_bounce_buffer = - mmap(NULL, X86_64_BB_SIZE * sizeof(x86_64_bounce), - PROT_EXEC|PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_32BIT|MAP_ANONYMOUS, -1, 0); - if (x86_64_bounce_buffer == MAP_FAILED) { - barf("x86_64_high_symbol: mmap failed"); - } - x86_64_bb_next_off = 0; - } - bounce = &x86_64_bounce_buffer[x86_64_bb_next_off]; - bounce->jmp[0] = 0xff; - bounce->jmp[1] = 0x25; - bounce->jmp[2] = 0x02; - bounce->jmp[3] = 0x00; - bounce->jmp[4] = 0x00; - bounce->jmp[5] = 0x00; - bounce->addr = addr; - x86_64_bb_next_off++; - - IF_DEBUG(linker, debugBelch("x86_64: allocated bounce entry for %s->%p at %p\n", - lbl, addr, bounce)); - - insertStrHashTable(symhash, lbl, bounce); - return bounce; -} -#endif - - /* * Generic ELF functions */ @@ -2850,9 +2858,12 @@ ocVerifyImage_ELF ( ObjectCode* oc ) case EM_PPC: IF_DEBUG(linker,debugBelch( "powerpc32" )); break; #ifdef EM_X86_64 case EM_X86_64: IF_DEBUG(linker,debugBelch( "x86_64" )); break; +#elif defined(EM_AMD64) + case EM_AMD64: IF_DEBUG(linker,debugBelch( "amd64" )); break; #endif default: IF_DEBUG(linker,debugBelch( "unknown" )); - errorBelch("%s: unknown architecture", oc->fileName); + errorBelch("%s: unknown architecture (e_machine == %d)" + , oc->fileName, ehdr->e_machine); return 0; } @@ -3460,28 +3471,73 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC, { StgInt64 off = value - P; if (off >= 0x7fffffffL || off < -0x80000000L) { - barf("R_X86_64_PC32 relocation out of range: %s = %p", - symbol, off); - } +#if X86_64_ELF_NONPIC_HACK + StgInt64 pltAddress = (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S) + -> jumpIsland; + off = pltAddress + A - P; +#else + barf("R_X86_64_PC32 relocation out of range: %s = %p\nRecompile %s with -fPIC.", + symbol, off, oc->fileName ); +#endif + } + *(Elf64_Word *)P = (Elf64_Word)off; + break; + } + + case R_X86_64_PC64: + { + StgInt64 off = value - P; *(Elf64_Word *)P = (Elf64_Word)off; break; } case R_X86_64_32: if (value >= 0x7fffffffL) { - barf("R_X86_64_32 relocation out of range: %s = %p\n", - symbol, value); - } +#if X86_64_ELF_NONPIC_HACK + StgInt64 pltAddress = (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S) + -> jumpIsland; + value = pltAddress + A; +#else + barf("R_X86_64_32 relocation out of range: %s = %p\nRecompile %s with -fPIC.", + symbol, value, oc->fileName ); +#endif + } *(Elf64_Word *)P = (Elf64_Word)value; break; case R_X86_64_32S: if ((StgInt64)value > 0x7fffffffL || (StgInt64)value < -0x80000000L) { - barf("R_X86_64_32S relocation out of range: %s = %p\n", - symbol, value); +#if X86_64_ELF_NONPIC_HACK + StgInt64 pltAddress = (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S) + -> jumpIsland; + value = pltAddress + A; +#else + barf("R_X86_64_32S relocation out of range: %s = %p\nRecompile %s with -fPIC.", + symbol, value, oc->fileName ); +#endif } *(Elf64_Sword *)P = (Elf64_Sword)value; break; + + case R_X86_64_GOTPCREL: + { + StgInt64 gotAddress = (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S)->addr; + StgInt64 off = gotAddress + A - P; + *(Elf64_Word *)P = (Elf64_Word)off; + break; + } + + case R_X86_64_PLT32: + { + StgInt64 off = value - P; + if (off >= 0x7fffffffL || off < -0x80000000L) { + StgInt64 pltAddress = (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S) + -> jumpIsland; + off = pltAddress + A - P; + } + *(Elf64_Word *)P = (Elf64_Word)off; + break; + } #endif default: @@ -3634,10 +3690,10 @@ ia64_reloc_pcrel21(Elf_Addr target, Elf_Addr value, ObjectCode *oc) #endif /* ia64 */ /* - * PowerPC ELF specifics + * PowerPC & X86_64 ELF specifics */ -#ifdef powerpc_HOST_ARCH +#if defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH) static int ocAllocateSymbolExtras_ELF( ObjectCode *oc ) { @@ -3661,7 +3717,7 @@ static int ocAllocateSymbolExtras_ELF( ObjectCode *oc ) 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 ) ); + (int) shdr[i].sh_entsize, (int) sizeof( Elf_Sym ) ); return 0; } @@ -4186,7 +4242,7 @@ static int relocateSection( #ifdef powerpc_HOST_ARCH // In the .o file, this should be a relative jump to NULL // and we'll change it to a relative jump to the symbol - ASSERT(-word == reloc->r_address); + ASSERT(word + reloc->r_address == 0); jumpIsland = (unsigned long) &makeSymbolExtra(oc, reloc->r_symbolnum,