diff options
author | Zejun Wu <watashi@fb.com> | 2018-10-15 13:52:53 -0400 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2018-10-15 19:24:17 -0400 |
commit | 8306141397d6e47a169dbe4b7ff1b3319a502aa7 (patch) | |
tree | 4397939b9508e4d2e06ced33d6568dd837784dfc | |
parent | 104599f3f157613589e78627c915e4dc20ee54b4 (diff) | |
download | haskell-8306141397d6e47a169dbe4b7ff1b3319a502aa7.tar.gz |
Allocate bss section within proper range of other sections
Allocate bss section within proper range of other sections:
* when `+RTS -xp` is passed, allocate it contiguously as we did for
jump islands
* when we mmap the code to lower 2Gb, we should allocate bss section
there too
This depends on {D5195}
Test Plan:
1. `./validate`
2.
with
```
DYNAMIC_GHC_PROGRAMS = NO
DYNAMIC_BY_DEFAULT = NO
```
`TEST="T15729" make test` passed in both linux and macos.
3.
Also test in a use case where we used to encouter error like:
```
ghc-iserv-prof: R_X86_64_PC32 relocation out of range: (noname) =
b90282ba
```
and now, everything works fine.
Reviewers: simonmar, bgamari, angerman, erikd
Reviewed By: simonmar
Subscribers: rwbarton, carter
GHC Trac Issues: #15729
Differential Revision: https://phabricator.haskell.org/D5219
-rw-r--r-- | rts/Linker.c | 22 | ||||
-rw-r--r-- | rts/LinkerInternals.h | 4 | ||||
-rw-r--r-- | rts/linker/Elf.c | 73 | ||||
-rw-r--r-- | rts/linker/Elf.h | 2 | ||||
-rw-r--r-- | rts/linker/MachO.c | 27 | ||||
-rw-r--r-- | rts/linker/MachO.h | 2 | ||||
-rw-r--r-- | rts/linker/PEi386.c | 2 | ||||
-rw-r--r-- | rts/linker/PEi386.h | 2 | ||||
-rw-r--r-- | rts/linker/SymbolExtras.c | 31 | ||||
-rw-r--r-- | rts/linker/SymbolExtras.h | 2 | ||||
-rw-r--r-- | rts/sm/OSMem.h | 10 | ||||
-rw-r--r-- | testsuite/tests/ghci/linking/Makefile | 5 | ||||
-rw-r--r-- | testsuite/tests/ghci/linking/T15729.c | 4 | ||||
-rw-r--r-- | testsuite/tests/ghci/linking/T15729.hs | 14 | ||||
-rw-r--r-- | testsuite/tests/ghci/linking/T15729.stdout | 2 | ||||
-rw-r--r-- | testsuite/tests/ghci/linking/all.T | 6 |
16 files changed, 132 insertions, 76 deletions
diff --git a/rts/Linker.c b/rts/Linker.c index b42a0de9c3..48d52c3f3d 100644 --- a/rts/Linker.c +++ b/rts/Linker.c @@ -1284,6 +1284,8 @@ mkOc( pathchar *path, char *image, int imageSize, #if defined(NEED_SYMBOL_EXTRAS) oc->symbol_extras = NULL; #endif + oc->bssBegin = NULL; + oc->bssEnd = NULL; oc->imageMapped = mapped; oc->misalignment = misalignment; @@ -1497,35 +1499,35 @@ HsInt loadOc (ObjectCode* oc) } /* Note [loadOc orderings] - The order of `ocAllocateSymbolExtras` and `ocGetNames` matters. For MachO + The order of `ocAllocateExtras` 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 + on the offset to `oc->image`, but `ocAllocateExtras` may relocate the address of `oc->image` and invalidate those pointers. So we must - compute or recompute those pointers after `ocAllocateSymbolExtras`. + compute or recompute those pointers after `ocAllocateExtras`. 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 + symbol table. Allocating space for jump tables in ocAllocateExtras would just be a waste then as we'll be stopping further processing of the library in the next few steps. If necessary, the actual allocation - happens in `ocGetNames_PEi386` and `ocAllocateSymbolExtras_PEi386` simply + happens in `ocGetNames_PEi386` and `ocAllocateExtras_PEi386` simply set the correct pointers. */ #if defined(NEED_SYMBOL_EXTRAS) # if defined(OBJFORMAT_MACHO) - r = ocAllocateSymbolExtras_MachO ( oc ); + r = ocAllocateExtras_MachO ( oc ); if (!r) { IF_DEBUG(linker, - debugBelch("loadOc: ocAllocateSymbolExtras_MachO failed\n")); + debugBelch("loadOc: ocAllocateExtras_MachO failed\n")); return r; } # elif defined(OBJFORMAT_ELF) - r = ocAllocateSymbolExtras_ELF ( oc ); + r = ocAllocateExtras_ELF ( oc ); if (!r) { IF_DEBUG(linker, - debugBelch("loadOc: ocAllocateSymbolExtras_ELF failed\n")); + debugBelch("loadOc: ocAllocateExtras_ELF failed\n")); return r; } # endif @@ -1546,7 +1548,7 @@ HsInt loadOc (ObjectCode* oc) } # if defined(OBJFORMAT_PEi386) - ocAllocateSymbolExtras_PEi386 ( oc ); + ocAllocateExtras_PEi386 ( oc ); # endif #endif diff --git a/rts/LinkerInternals.h b/rts/LinkerInternals.h index 04d873ca99..9c34c18aef 100644 --- a/rts/LinkerInternals.h +++ b/rts/LinkerInternals.h @@ -193,6 +193,10 @@ typedef struct _ObjectCode { unsigned long first_symbol_extra; unsigned long n_symbol_extras; #endif + /* Additional memory that is preallocated and contiguous with image + which can be used used to relocate bss sections. */ + char* bssBegin; + char* bssEnd; ForeignExportStablePtr *stable_ptrs; diff --git a/rts/linker/Elf.c b/rts/linker/Elf.c index fe87aed0b0..0a7ffaec21 100644 --- a/rts/linker/Elf.c +++ b/rts/linker/Elf.c @@ -579,7 +579,7 @@ ocVerifyImage_ELF ( ObjectCode* oc ) /* Figure out what kind of section it is. Logic derived from Figure 1.14 ("Special Sections") of the ELF document ("Portable Formats Specification, Version 1.1"). */ -static int getSectionKind_ELF( Elf_Shdr *hdr, int *is_bss ) +static SectionKind getSectionKind_ELF( Elf_Shdr *hdr, int *is_bss ) { *is_bss = false; @@ -681,23 +681,31 @@ ocGetNames_ELF ( ObjectCode* oc ) StgWord mapped_size = 0, mapped_offset = 0; StgWord size = shdr[i].sh_size; StgWord offset = shdr[i].sh_offset; + StgWord align = shdr[i].sh_addralign; if (is_bss && size > 0) { /* This is a non-empty .bss section. Allocate zeroed space for it, and set its .sh_offset field such that ehdrC + .sh_offset == addr_of_zeroed_space. */ -#if defined(NEED_GOT) - /* always use mmap if we use GOT slots. Otherwise the malloced - * address might be out of range for sections that are mmaped. - */ - alloc = SECTION_MMAP; - start = mmap(NULL, size, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_ANON | MAP_PRIVATE, - -1, 0); - mapped_start = start; - mapped_offset = 0; - mapped_size = roundUpToPage(size); +#if defined(NEED_GOT) || RTS_LINKER_USE_MMAP + if (USE_CONTIGUOUS_MMAP || RtsFlags.MiscFlags.linkerAlwaysPic) { + /* The space for bss sections is already preallocated */ + ASSERT(oc->bssBegin != NULL); + alloc = SECTION_NOMEM; + start = + oc->image + roundUpToAlign(oc->bssBegin - oc->image, align); + oc->bssBegin = (char*)start + size; + ASSERT(oc->bssBegin <= oc->bssEnd); + } else { + /* Use mmapForLinker to allocate .bss, otherwise the malloced + * address might be out of range for sections that are mmaped. + */ + alloc = SECTION_MMAP; + start = mmapForLinker(size, MAP_ANONYMOUS, -1, 0); + mapped_start = start; + mapped_offset = 0; + mapped_size = roundUpToPage(size); + } #else alloc = SECTION_MALLOC; start = stgCallocBytes(1, size, "ocGetNames_ELF(BSS)"); @@ -1873,22 +1881,27 @@ int ocRunInit_ELF( ObjectCode *oc ) #if defined(NEED_SYMBOL_EXTRAS) -int ocAllocateSymbolExtras_ELF( ObjectCode *oc ) +int ocAllocateExtras_ELF( ObjectCode *oc ) { - Elf_Ehdr *ehdr; - Elf_Shdr* shdr; - Elf_Word i, shnum; - - ehdr = (Elf_Ehdr *) oc->image; - shdr = (Elf_Shdr *) ( ((char *)oc->image) + ehdr->e_shoff ); - - shnum = elf_shnum(ehdr); - - for( i = 0; i < shnum; i++ ) - if( shdr[i].sh_type == SHT_SYMTAB ) - break; + Elf_Ehdr *ehdr = (Elf_Ehdr *) oc->image; + Elf_Shdr* shdr = (Elf_Shdr *) ( ((char *)oc->image) + ehdr->e_shoff ); + Elf_Shdr* symtab = NULL; + Elf_Word shnum = elf_shnum(ehdr); + int bssSize = 0; + + for (Elf_Word i = 0; i < shnum; ++i) { + if(shdr[i].sh_type == SHT_SYMTAB) { + symtab = &shdr[i]; + } else { + int isBss = 0; + getSectionKind_ELF(&shdr[i], &isBss); + if (isBss && shdr[i].sh_size > 0) { + bssSize += roundUpToAlign(shdr[i].sh_size, shdr[i].sh_addralign); + } + } + } - if( i == shnum ) + if (symtab == NULL) { // Not having a symbol table is not in principle a problem. // When an object file has no symbols then the 'strip' program @@ -1898,15 +1911,15 @@ int ocAllocateSymbolExtras_ELF( ObjectCode *oc ) return 1; } - if( shdr[i].sh_entsize != sizeof( Elf_Sym ) ) + if( symtab->sh_entsize != sizeof( Elf_Sym ) ) { errorBelch( "The entry size (%d) of the symtab isn't %d\n", - (int) shdr[i].sh_entsize, (int) sizeof( Elf_Sym ) ); + (int) symtab->sh_entsize, (int) sizeof( Elf_Sym ) ); return 0; } - return ocAllocateSymbolExtras( oc, shdr[i].sh_size / sizeof( Elf_Sym ), 0 ); + return ocAllocateExtras(oc, symtab->sh_size / sizeof( Elf_Sym ), 0, bssSize); } #endif /* NEED_SYMBOL_EXTRAS */ diff --git a/rts/linker/Elf.h b/rts/linker/Elf.h index b0d6638e6a..30c993b98c 100644 --- a/rts/linker/Elf.h +++ b/rts/linker/Elf.h @@ -13,6 +13,6 @@ int ocVerifyImage_ELF ( ObjectCode* oc ); int ocGetNames_ELF ( ObjectCode* oc ); int ocResolve_ELF ( ObjectCode* oc ); int ocRunInit_ELF ( ObjectCode* oc ); -int ocAllocateSymbolExtras_ELF( ObjectCode *oc ); +int ocAllocateExtras_ELF ( ObjectCode *oc ); #include "EndPrivate.h" diff --git a/rts/linker/MachO.c b/rts/linker/MachO.c index ff8ef7a1e4..7d5ff32276 100644 --- a/rts/linker/MachO.c +++ b/rts/linker/MachO.c @@ -186,10 +186,10 @@ resolveImports( #if NEED_SYMBOL_EXTRAS #if defined(powerpc_HOST_ARCH) int -ocAllocateSymbolExtras_MachO(ObjectCode* oc) +ocAllocateExtras_MachO(ObjectCode* oc) { - IF_DEBUG(linker, debugBelch("ocAllocateSymbolExtras_MachO: start\n")); + IF_DEBUG(linker, debugBelch("ocAllocateExtras_MachO: start\n")); // Find out the first and last undefined external // symbol, so we don't have to allocate too many @@ -218,28 +218,31 @@ ocAllocateSymbolExtras_MachO(ObjectCode* oc) } if (max >= min) { - return ocAllocateSymbolExtras(oc, max - min + 1, min); + return ocAllocateExtras(oc, max - min + 1, min, 0); } - return ocAllocateSymbolExtras(oc,0,0); + return ocAllocateExtras(oc, 0, 0, 0); } #elif defined(x86_64_HOST_ARCH) || defined(aarch64_HOST_ARCH) int -ocAllocateSymbolExtras_MachO(ObjectCode* oc) +ocAllocateExtras_MachO(ObjectCode* oc) { - IF_DEBUG(linker, debugBelch("ocAllocateSymbolExtras_MachO: start\n")); + IF_DEBUG(linker, debugBelch("ocAllocateExtras_MachO: start\n")); if (NULL != oc->info->symCmd) { - IF_DEBUG(linker, debugBelch("ocAllocateSymbolExtras_MachO: allocate %d symbols\n", oc->info->symCmd->nsyms)); - IF_DEBUG(linker, debugBelch("ocAllocateSymbolExtras_MachO: done\n")); - return ocAllocateSymbolExtras(oc, oc->info->symCmd->nsyms, 0); + IF_DEBUG(linker, + debugBelch("ocAllocateExtras_MachO: allocate %d symbols\n", + oc->info->symCmd->nsyms)); + IF_DEBUG(linker, debugBelch("ocAllocateExtras_MachO: done\n")); + return ocAllocateExtras(oc, oc->info->symCmd->nsyms, 0, 0); } - IF_DEBUG(linker, debugBelch("ocAllocateSymbolExtras_MachO: allocated no symbols\n")); - IF_DEBUG(linker, debugBelch("ocAllocateSymbolExtras_MachO: done\n")); - return ocAllocateSymbolExtras(oc,0,0); + IF_DEBUG(linker, + debugBelch("ocAllocateExtras_MachO: allocated no symbols\n")); + IF_DEBUG(linker, debugBelch("ocAllocateExtras_MachO: done\n")); + return ocAllocateExtras(oc, 0, 0, 0); } #else diff --git a/rts/linker/MachO.h b/rts/linker/MachO.h index b495c2b9b1..4fb58e8668 100644 --- a/rts/linker/MachO.h +++ b/rts/linker/MachO.h @@ -13,7 +13,7 @@ int ocGetNames_MachO ( ObjectCode* oc ); int ocResolve_MachO ( ObjectCode* oc ); int ocRunInit_MachO ( ObjectCode* oc ); int machoGetMisalignment( FILE * ); -int ocAllocateSymbolExtras_MachO ( ObjectCode* oc ); +int ocAllocateExtras_MachO ( ObjectCode* oc ); #if defined(powerpc_HOST_ARCH) void machoInitSymbolsWithoutUnderscore( void ); diff --git a/rts/linker/PEi386.c b/rts/linker/PEi386.c index ab4583da7c..bf642d8b23 100644 --- a/rts/linker/PEi386.c +++ b/rts/linker/PEi386.c @@ -1777,7 +1777,7 @@ ocGetNames_PEi386 ( ObjectCode* oc ) * so simply set correct pointer here. */ bool -ocAllocateSymbolExtras_PEi386 ( ObjectCode* oc ) +ocAllocateExtras_PEi386 ( ObjectCode* oc ) { /* If the ObjectCode was unloaded we don't need a trampoline, it's likely an import library so we're discarding it earlier. */ diff --git a/rts/linker/PEi386.h b/rts/linker/PEi386.h index eb5bec8b78..538f132ab5 100644 --- a/rts/linker/PEi386.h +++ b/rts/linker/PEi386.h @@ -57,7 +57,7 @@ bool ocRunInit_PEi386 ( ObjectCode *oc ); bool ocGetNames_PEi386 ( ObjectCode* oc ); bool ocVerifyImage_PEi386 ( ObjectCode* oc ); SymbolAddr *lookupSymbol_PEi386(SymbolName *lbl); -bool ocAllocateSymbolExtras_PEi386 ( ObjectCode* oc ); +bool ocAllocateExtras_PEi386 ( ObjectCode* oc ); SymbolAddr *lookupSymbolInDLLs ( const SymbolName* lbl ); /* See Note [mingw-w64 name decoration scheme] */ /* We use myindex to calculate array addresses, rather than diff --git a/rts/linker/SymbolExtras.c b/rts/linker/SymbolExtras.c index 4c40b10877..a9e4c37967 100644 --- a/rts/linker/SymbolExtras.c +++ b/rts/linker/SymbolExtras.c @@ -31,10 +31,11 @@ #endif /* RTS_LINKER_USE_MMAP */ /* - ocAllocateSymbolExtras + ocAllocateExtras Allocate additional space at the end of the object file image to make room - for jump islands (powerpc, x86_64, arm) and GOT entries (x86_64). + for jump islands (powerpc, x86_64, arm), GOT entries (x86_64) and + bss sections. PowerPC relative branch instructions have a 24 bit displacement field. As PPC code is always 4-byte-aligned, this yields a +-32MB range. @@ -49,12 +50,11 @@ filled in by makeSymbolExtra below. */ -int ocAllocateSymbolExtras( ObjectCode* oc, int count, int first ) +int ocAllocateExtras(ObjectCode* oc, int count, int first, int bssSize) { - size_t n; void* oldImage = oc->image; - if (count > 0) { + if (count > 0 || bssSize > 0) { if (!RTS_LINKER_USE_MMAP) { // round up to the nearest 4 @@ -65,16 +65,15 @@ int ocAllocateSymbolExtras( ObjectCode* oc, int count, int first ) oc->image = stgReallocBytes( oc->image, misalignment + aligned + sizeof (SymbolExtra) * count, - "ocAllocateSymbolExtras" ); + "ocAllocateExtras" ); oc->image += misalignment; oc->symbol_extras = (SymbolExtra *) (oc->image + aligned); } else if (USE_CONTIGUOUS_MMAP || RtsFlags.MiscFlags.linkerAlwaysPic) { - n = roundUpToPage(oc->fileSize); - - /* Keep image and symbol_extras contiguous */ - - size_t allocated_size = n + (sizeof(SymbolExtra) * count); + /* Keep image, bssExtras and symbol_extras contiguous */ + size_t n = roundUpToPage(oc->fileSize); + bssSize = roundUpToAlign(bssSize, 8); + size_t allocated_size = n + bssSize + (sizeof(SymbolExtra) * count); void *new = mmapForLinker(allocated_size, MAP_ANONYMOUS, -1, 0); if (new) { memcpy(new, oc->image, oc->fileSize); @@ -83,12 +82,10 @@ int ocAllocateSymbolExtras( ObjectCode* oc, int count, int first ) } oc->image = new; oc->imageMapped = true; - oc->fileSize = n + (sizeof(SymbolExtra) * count); - oc->symbol_extras = (SymbolExtra *) (oc->image + n); - if (mprotect(new, allocated_size, - PROT_READ | PROT_WRITE | PROT_EXEC) != 0) { - sysErrorBelch("unable to protect memory"); - } + oc->fileSize = allocated_size; + oc->symbol_extras = (SymbolExtra *) (oc->image + n + bssSize); + oc->bssBegin = oc->image + n; + oc->bssEnd = oc->image + n + bssSize; } else { oc->symbol_extras = NULL; diff --git a/rts/linker/SymbolExtras.h b/rts/linker/SymbolExtras.h index 4974c06e7d..af828e66fa 100644 --- a/rts/linker/SymbolExtras.h +++ b/rts/linker/SymbolExtras.h @@ -7,7 +7,7 @@ #if defined(NEED_SYMBOL_EXTRAS) -int ocAllocateSymbolExtras( ObjectCode* oc, int count, int first ); +int ocAllocateExtras(ObjectCode* oc, int count, int first, int bssSize); #if defined(arm_HOST_ARCH) SymbolExtra* makeArmSymbolExtra( ObjectCode const* oc, diff --git a/rts/sm/OSMem.h b/rts/sm/OSMem.h index 7dd0efdc23..ea123e80c6 100644 --- a/rts/sm/OSMem.h +++ b/rts/sm/OSMem.h @@ -32,10 +32,16 @@ roundDownToPage (size_t x) } INLINE_HEADER size_t +roundUpToAlign (size_t size, size_t align) +{ + /* alignment must always be a power of 2 */ + return (size + align - 1) & ~(align - 1); +} + +INLINE_HEADER size_t roundUpToPage (size_t x) { - size_t size = getPageSize(); - return ((x + size - 1) & ~(size - 1)); + return roundUpToAlign(x, getPageSize()); } diff --git a/testsuite/tests/ghci/linking/Makefile b/testsuite/tests/ghci/linking/Makefile index 793998eb92..3ecc3c3447 100644 --- a/testsuite/tests/ghci/linking/Makefile +++ b/testsuite/tests/ghci/linking/Makefile @@ -134,3 +134,8 @@ T14708: "$(TEST_HC)" -c add.c -o T14708scratch/add.o "$(AR)" cqs T14708scratch/libadd.a T14708scratch/add.o -"$(TEST_HC)" $(TEST_HC_OPTS_INTERACTIVE) -LT14708scratch -ladd T14708.hs + +.PHONY: T15729 +T15729: + "$(TEST_HC)" -c T15729.c -o bss.o + echo "main" | "$(TEST_HC)" $(TEST_HC_OPTS_INTERACTIVE) bss.o T15729.hs diff --git a/testsuite/tests/ghci/linking/T15729.c b/testsuite/tests/ghci/linking/T15729.c new file mode 100644 index 0000000000..67cc6cd173 --- /dev/null +++ b/testsuite/tests/ghci/linking/T15729.c @@ -0,0 +1,4 @@ +int readBss(int i) { + static int bss[1 << 20]; + return bss[i]; +} diff --git a/testsuite/tests/ghci/linking/T15729.hs b/testsuite/tests/ghci/linking/T15729.hs new file mode 100644 index 0000000000..f35f96eac1 --- /dev/null +++ b/testsuite/tests/ghci/linking/T15729.hs @@ -0,0 +1,14 @@ +module T15729 (main) where + +import Foreign +import Foreign.C + +foreign import ccall unsafe "readBss" + readBss :: Int -> IO Int + +main :: IO () +main = do + prefix <- mapM readBss [0 .. 10] + print prefix + samples <- mapM readBss [0, 19 .. bit 20 - 1] + print $ foldr1 (.|.) samples diff --git a/testsuite/tests/ghci/linking/T15729.stdout b/testsuite/tests/ghci/linking/T15729.stdout new file mode 100644 index 0000000000..2a408d0e6d --- /dev/null +++ b/testsuite/tests/ghci/linking/T15729.stdout @@ -0,0 +1,2 @@ +[0,0,0,0,0,0,0,0,0,0,0] +0 diff --git a/testsuite/tests/ghci/linking/all.T b/testsuite/tests/ghci/linking/all.T index f9617c5cf7..16d91f1f71 100644 --- a/testsuite/tests/ghci/linking/all.T +++ b/testsuite/tests/ghci/linking/all.T @@ -39,3 +39,9 @@ test('T14708', extra_clean(['T14708scratch/*', 'T14708'])], run_command, ['$MAKE -s --no-print-directory T14708']) + +test('T15729', + [extra_files(['T15729.hs', 'T15729.c']), + unless(doing_ghci, skip)], + run_command, + ['$MAKE -s --no-print-directory T15729']) |