X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=rts%2FLinker.c;h=e2391842a29150091412778cff3d806e00d58240;hb=53a442f10d80cd85b33620a023c4a8749a7c0b20;hp=853bf77dd2c5d852751d9617bf5bb30c3f90d33c;hpb=afb559c1bcb64d407ce81ef3239306a2e650b1a7;p=ghc-hetmet.git diff --git a/rts/Linker.c b/rts/Linker.c index 853bf77..e239184 100644 --- a/rts/Linker.c +++ b/rts/Linker.c @@ -107,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) @@ -128,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 @@ -153,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) @@ -440,6 +463,23 @@ typedef struct _RtsSymbolVal { SymX(stg_ap_pppppp_ret) #endif +/* On Windows, we link libgmp.a statically into libHSrts.dll */ +#ifdef mingw32_HOST_OS +#define GMP_SYMS \ + SymX(__gmpz_cmp) \ + SymX(__gmpz_cmp_si) \ + SymX(__gmpz_cmp_ui) \ + SymX(__gmpz_get_si) \ + SymX(__gmpz_get_ui) +#else +#define GMP_SYMS \ + SymExtern(__gmpz_cmp) \ + SymExtern(__gmpz_cmp_si) \ + SymExtern(__gmpz_cmp_ui) \ + SymExtern(__gmpz_get_si) \ + SymExtern(__gmpz_get_ui) +#endif + #define RTS_SYMBOLS \ Maybe_Stable_Names \ Sym(StgReturn) \ @@ -479,12 +519,7 @@ typedef struct _RtsSymbolVal { SymX(__encodeDouble) \ SymX(__encodeFloat) \ SymX(addDLL) \ - SymExtern(__gmpn_gcd_1) \ - SymExtern(__gmpz_cmp) \ - SymExtern(__gmpz_cmp_si) \ - SymExtern(__gmpz_cmp_ui) \ - SymExtern(__gmpz_get_si) \ - SymExtern(__gmpz_get_ui) \ + GMP_SYMS \ SymX(__int_encodeDouble) \ SymX(__int_encodeFloat) \ SymX(andIntegerzh_fast) \ @@ -646,7 +681,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) \ @@ -1058,19 +1094,7 @@ 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 @@ -1349,7 +1373,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 @@ -1531,8 +1555,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 @@ -1559,10 +1582,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 ) { @@ -2743,64 +2768,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|EXTRA_MAP_FLAGS|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 */ @@ -2903,8 +2870,7 @@ 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; -#endif -#ifdef EM_AMD64 +#elif defined(EM_AMD64) case EM_AMD64: IF_DEBUG(linker,debugBelch( "amd64" )); break; #endif default: IF_DEBUG(linker,debugBelch( "unknown" )); @@ -3517,9 +3483,15 @@ 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; } @@ -3533,19 +3505,51 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC, 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: @@ -3698,10 +3702,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 ) { @@ -3725,7 +3729,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; }