diff options
author | Zejun Wu <watashi@fb.com> | 2018-10-15 13:52:36 -0400 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2018-10-15 19:24:16 -0400 |
commit | 104599f3f157613589e78627c915e4dc20ee54b4 (patch) | |
tree | e640f6b00972a83a0dda163757cf144acd4ef70d /rts/Linker.c | |
parent | 165d3d5ddaecc7dbe7f5ac051834a7619463efb0 (diff) | |
download | haskell-104599f3f157613589e78627c915e4dc20ee54b4.tar.gz |
Add a RTS option -xp to load PIC object anywhere in address space
Add a RTS option -xp to load PIC object anywhere in address space. We do
this by relaxing the requirement of <0x80000000 result of
`mmapForLinker` and implying USE_CONTIGUOUS_MMAP.
We also need to change calls to `ocInit` and `ocGetNames` to avoid
dangling pointers when the address of `oc->image` is changed by
`ocAllocateSymbolExtra`.
Test Plan:
```
$ uname -a
Linux localhost 4.18.8-arch1-1-ARCH #1 SMP PREEMPT Sat Sep 15 20:34:48
UTC 2018 x86_64 GNU/Linux
$ cat mk/build.mk
DYNAMIC_GHC_PROGRAMS = NO
DYNAMIC_BY_DEFAULT = NO
GhcRTSWays += thr_debug
EXTRA_HC_OPTS += -debug
WAY_p_HC_OPTS += -fPIC -fexternal-dynamic-refs
$ inplace/bin/ghc-stage2 --interactive -prof +RTS -xp
GHCi, version 8.7.20180928: http://www.haskell.org/ghc/ :? for help
ghc-stage2: R_X86_64_32 relocation out of range:
ghczmprim_GHCziTypes_ZMZN_closure = 7f690bffab59
Recompile
/data/users/watashi/ghc/libraries/ghc-prim/dist-install/build/HSghc-prim
-0.5.3.o with -fPIC -fexternal-dynamic-refs.
ghc-stage2: unable to load package `ghc-prim-0.5.3'
$ strace -f -e open,mmap inplace/bin/ghc-stage2 --interactive -prof
-fexternal-interpreter -opti+RTS -opti-xp
...
[pid 1355283]
open("/data/users/watashi/ghc/libraries/base/dist-install/build/libHSbas
e-4.12.0.0_p.a", O_RDONLY) = 14
[pid 1355283] mmap(NULL, 8192, PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f6a84842000
[pid 1355283]
open("/data/users/watashi/ghc/libraries/base/dist-install/build/libHSbas
e-4.12.0.0_p.a", O_RDONLY) = 14
[pid 1355283] mmap(NULL, 8192, PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f6a84676000
...
Prelude> System.Posix.Process.getProcessID
...
[pid 1355283]
open("/data/users/watashi/ghc/libraries/unix/dist-install/build/libHSuni
x-2.7.2.2_p.a", O_RDONLY) = 14
[pid 1355283] mmap(NULL, 45056, PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f6a67d60000
[pid 1355283]
open("/data/users/watashi/ghc/libraries/unix/dist-install/build/libHSuni
x-2.7.2.2_p.a", O_RDONLY) = 14
[pid 1355283] mmap(NULL, 57344, PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f6a67d52000
...
```
```
$ uname -a
Darwin watashis-iMac.local 18.0.0 Darwin Kernel Version 18.0.0: Wed Aug
22 20:13:40 PDT 2018; root:xnu-4903.201.2~1/RELEASE_X86_64 x86_64
$ mv
/Users/watashi/gao/ghc/libraries/integer-gmp/dist-install/build/HSintege
r-gmp-1.0.2.0.o{,._DISABLE_GHC_ISSUE_15105}
$ inplace/bin/ghc-stage2 --interactive +RTS -xp
GHCi, version 8.7.20181003: http://www.haskell.org/ghc/ :? for help
Prelude> System.Posix.Process.getProcessID
42791
Prelude> Data.Set.fromList [1 .. 10]
fromList [1,2,3,4,5,6,7,8,9,10]
Prelude>
Leaving GHCi.
$ inplace/bin/ghc-stage2 --interactive -prof -fexternal-interpreter
GHCi, version 8.7.20181003: http://www.haskell.org/ghc/ :? for help
Prelude> System.Posix.Process.getProcessID
42806
Prelude> Data.Set.fromList [1 .. 10]
fromList [1,2,3,4,5,6,7,8,9,10]
Prelude>
Leaving GHCi.
```
Also test with something that used to hit the 2Gb limit and it loads
and runs without problem.
Reviewers: simonmar, bgamari, angerman, Phyx, hvr, erikd
Reviewed By: simonmar
Subscribers: rwbarton, carter
Differential Revision: https://phabricator.haskell.org/D5195
Diffstat (limited to 'rts/Linker.c')
-rw-r--r-- | rts/Linker.c | 80 |
1 files changed, 39 insertions, 41 deletions
diff --git a/rts/Linker.c b/rts/Linker.c index 826269738b..b42a0de9c3 100644 --- a/rts/Linker.c +++ b/rts/Linker.c @@ -72,10 +72,6 @@ # include <mach-o/fat.h> #endif -#if defined(x86_64_HOST_ARCH) && defined(darwin_HOST_OS) -#define ALWAYS_PIC -#endif - #if defined(dragonfly_HOST_OS) #include <sys/tls.h> #endif @@ -212,9 +208,7 @@ int ocTryLoad( ObjectCode* oc ); * We pick a default address based on the OS, but also make this * configurable via an RTS flag (+RTS -xm) */ -#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH) - -#if defined(MAP_32BIT) +#if defined(MAP_32BIT) || DEFAULT_LINKER_ALWAYS_PIC // Try to use MAP_32BIT #define MMAP_32BIT_BASE_DEFAULT 0 #else @@ -223,7 +217,6 @@ int ocTryLoad( ObjectCode* oc ); #endif static void *mmap_32bit_base = (void *)MMAP_32BIT_BASE_DEFAULT; -#endif static void ghciRemoveSymbolTable(HashTable *table, const SymbolName* key, ObjectCode *owner) @@ -496,12 +489,10 @@ initLinker_ (int retain_cafs) } # endif -#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 if (RTS_LINKER_USE_MMAP) m32_allocator_init(); @@ -1009,29 +1000,30 @@ mmapForLinker (size_t bytes, uint32_t flags, int fd, int offset) void *map_addr = NULL; void *result; size_t size; + uint32_t tryMap32Bit = RtsFlags.MiscFlags.linkerAlwaysPic + ? 0 + : TRY_MAP_32BIT; static uint32_t fixed = 0; IF_DEBUG(linker, debugBelch("mmapForLinker: start\n")); size = roundUpToPage(bytes); -#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH) mmap_again: if (mmap_32bit_base != 0) { map_addr = mmap_32bit_base; } -#endif IF_DEBUG(linker, debugBelch("mmapForLinker: \tprotection %#0x\n", PROT_EXEC | PROT_READ | PROT_WRITE)); IF_DEBUG(linker, debugBelch("mmapForLinker: \tflags %#0x\n", - MAP_PRIVATE | TRY_MAP_32BIT | fixed | flags)); + MAP_PRIVATE | tryMap32Bit | fixed | flags)); result = mmap(map_addr, size, PROT_EXEC|PROT_READ|PROT_WRITE, - MAP_PRIVATE|TRY_MAP_32BIT|fixed|flags, fd, offset); + MAP_PRIVATE|tryMap32Bit|fixed|flags, fd, offset); if (result == MAP_FAILED) { sysErrorBelch("mmap %" FMT_Word " bytes at %p",(W_)size,map_addr); @@ -1039,8 +1031,9 @@ mmap_again: return NULL; } -#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH) - if (mmap_32bit_base != 0) { +#if defined(x86_64_HOST_ARCH) + if (RtsFlags.MiscFlags.linkerAlwaysPic) { + } else if (mmap_32bit_base != 0) { if (result == map_addr) { mmap_32bit_base = (StgWord8*)map_addr + size; } else { @@ -1208,10 +1201,10 @@ void freeObjectCode (ObjectCode *oc) #if defined(NEED_SYMBOL_EXTRAS) && (!defined(x86_64_HOST_ARCH) \ || !defined(mingw32_HOST_OS)) if (RTS_LINKER_USE_MMAP) { - if (!USE_CONTIGUOUS_MMAP && oc->symbol_extras != NULL) { - m32_free(oc->symbol_extras, - sizeof(SymbolExtra) * oc->n_symbol_extras); - } + if (!USE_CONTIGUOUS_MMAP && !RtsFlags.MiscFlags.linkerAlwaysPic && + oc->symbol_extras != NULL) { + m32_free(oc->symbol_extras, sizeof(SymbolExtra) * oc->n_symbol_extras); + } } else { stgFree(oc->symbol_extras); @@ -1504,32 +1497,21 @@ HsInt loadOc (ObjectCode* oc) } /* Note [loadOc orderings] - ocAllocateSymbolsExtras has only two pre-requisites, it must run after - preloadObjectFile and ocVerify. Neither have changed. On most targets - allocating the extras is independent on parsing the section data, so the - order between these two never mattered. + The order of `ocAllocateSymbolExtras` and `ocGetNames` matters. For MachO + and ELF, `ocInit` and `ocGetNames` initialize a bunch of pointers based + on the offset to `oc->image`, but `ocAllocateSymbolExtras` may relocate + the address of `oc->image` and invalidate those pointers. So we must + compute or recompute those pointers after `ocAllocateSymbolExtras`. On Windows, when we have an import library we (for now, as we don't honor the lazy loading semantics of the library and instead GHCi is already lazy) don't use the library after ocGetNames as it just populates the symbol table. Allocating space for jump tables in ocAllocateSymbolExtras would just be a waste then as we'll be stopping further processing of the - library in the next few steps. */ - - /* build the symbol list for this image */ -# if defined(OBJFORMAT_ELF) - r = ocGetNames_ELF ( oc ); -# elif defined(OBJFORMAT_PEi386) - r = ocGetNames_PEi386 ( oc ); -# elif defined(OBJFORMAT_MACHO) - r = ocGetNames_MachO ( oc ); -# else - barf("loadObj: no getNames method"); -# endif - if (!r) { - IF_DEBUG(linker, debugBelch("loadOc: ocGetNames_* failed\n")); - return r; - } + library in the next few steps. If necessary, the actual allocation + happens in `ocGetNames_PEi386` and `ocAllocateSymbolExtras_PEi386` simply + set the correct pointers. + */ #if defined(NEED_SYMBOL_EXTRAS) # if defined(OBJFORMAT_MACHO) @@ -1546,7 +1528,24 @@ HsInt loadOc (ObjectCode* oc) debugBelch("loadOc: ocAllocateSymbolExtras_ELF failed\n")); return r; } +# endif + + /* build the symbol list for this image */ +# if defined(OBJFORMAT_ELF) + r = ocGetNames_ELF ( oc ); # elif defined(OBJFORMAT_PEi386) + r = ocGetNames_PEi386 ( oc ); +# elif defined(OBJFORMAT_MACHO) + r = ocGetNames_MachO ( oc ); +# else + barf("loadObj: no getNames method"); +# endif + if (!r) { + IF_DEBUG(linker, debugBelch("loadOc: ocGetNames_* failed\n")); + return r; + } + +# if defined(OBJFORMAT_PEi386) ocAllocateSymbolExtras_PEi386 ( oc ); # endif #endif @@ -1830,4 +1829,3 @@ addSection (Section *s, SectionKind kind, SectionAlloc alloc, start, (void*)((StgWord)start + size), size, kind )); } - |