Commit 740534d4 authored by Zejun Wu's avatar Zejun Wu Committed by Ben Gamari

Allocate bss section within proper range of other sections

Summary:
This re-applies {D5195} and {D5235}, they were reverted as part of diff
stack to unbreak i386. The proper fix is done in {D5289}.

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

Test Plan:
1. `./validate`

2.

with

```
DYNAMIC_GHC_PROGRAMS = NO
DYNAMIC_BY_DEFAULT = NO
```

`TEST="T15729" make test` passed in both linux (both i386 and x86_64) 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/D5290
parent e29b1ee7
......@@ -1286,6 +1286,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;
......@@ -1499,35 +1501,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
......@@ -1550,7 +1552,7 @@ HsInt loadOc (ObjectCode* oc)
#if defined(NEED_SYMBOL_EXTRAS)
# if defined(OBJFORMAT_PEi386)
ocAllocateSymbolExtras_PEi386 ( oc );
ocAllocateExtras_PEi386 ( oc );
# endif
#endif
......
......@@ -201,6 +201,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;
......
......@@ -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)");
......@@ -1874,22 +1882,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
......@@ -1899,15 +1912,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 */
......
......@@ -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"
......@@ -187,19 +187,22 @@ resolveImports(
#if 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
......
......@@ -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 );
......
......@@ -1778,7 +1778,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. */
......
......@@ -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
......
......@@ -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;
......
......@@ -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,
......
......@@ -31,11 +31,17 @@ roundDownToPage (size_t x)
return (x & ~(size - 1));
}
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());
}
......
......@@ -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)" -fPIC -c T15729.c -o bss.o
echo "main" | "$(TEST_HC)" $(TEST_HC_OPTS_INTERACTIVE) bss.o T15729.hs
int readBss(int i) {
static int bss[1 << 20];
return bss[i];
}
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
......@@ -40,3 +40,8 @@ test('T14708',
unless(ghc_dynamic(), skip),
extra_clean(['T14708scratch/*', 'T14708'])],
makefile_test, ['T14708'])
test('T15729',
[extra_files(['T15729.hs', 'T15729.c']),
unless(doing_ghci, skip)],
makefile_test, ['T15729'])
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment