Commit 82a71643 authored by Ben Gamari's avatar Ben Gamari 🐢

Revert "Add a RTS option -xp to load PIC object anywhere in address space"

This reverts commit 5403a863.
parent 9cbf6f2b
......@@ -80,10 +80,6 @@ Runtime system
alignment, lower the amount of wasted memory and lower the amount of in use memory.
See :ghc-ticket:`13617`. Note that committed memory may be slightly higher.
- A new flag ``-xp`` is added on x86_64. When it is passed, the runtime linker
can load object files compiled with ``-fPIC -fexternal-dynamic-refs``
anywhere in the address space. This used to be restricted to the low 2Gb.
Template Haskell
~~~~~~~~~~~~~~~~
......
......@@ -241,28 +241,6 @@ Miscellaneous RTS options
crashes if exception handling are enabled. In order to get more information
in compiled executables, C code or DLLs symbols need to be available.
.. rts-flag:: -xp
On 64-bit machines, the runtime linker usually needs to map object code
into the low 2Gb of the address space, due to the x86_64 small memory model
where most symbol references are 32 bits. The problem is that this 2Gb of
address space can fill up, especially if you're loading a very large number
of object files into GHCi.
This flag offers a workaround, albeit a slightly convoluted one. To be able
to load an object file outside of the low 2Gb, the object code needs to be
compiled with ``-fPIC -fexternal-dynamic-refs``. When the ``+RTS -xp`` flag
is passed, the linker will assume that all object files were compiled with
``-fPIC -fexternal-dynamic-refs`` and load them anywhere in the address
space. It's up to you to arrange that the object files you load (including
all packages) were compiled in the right way. If this is not the case for
an object, the linker will probably fail with an error message when the
problem is detected.
On some platforms where PIC is always the case, e.g. x86_64 MacOS X, this
flag is enabled by default.
.. rts-flag:: -xm ⟨address⟩
.. index::
......@@ -272,10 +250,8 @@ Miscellaneous RTS options
This option is for working around memory allocation
problems only. Do not use unless GHCi fails with a message like
“\ ``failed to mmap() memory below 2Gb``\ ”. Consider recompiling
the objects with ``-fPIC -fexternal-dynamic-refs`` and using the
``-xp`` flag instead. If you need to use this option to get GHCi
working on your machine, please file a bug.
“\ ``failed to mmap() memory below 2Gb``\ ”. If you need to use this
option to get GHCi working on your machine, please file a bug.
On 64-bit machines, the RTS needs to allocate memory in the low 2Gb
of the address space. Support for this across different operating
......
......@@ -187,17 +187,6 @@ typedef struct _CONCURRENT_FLAGS {
*/
#define DEFAULT_TICK_INTERVAL USToTime(10000)
/*
* When linkerAlwaysPic is true, the runtime linker assume that all object
* files were compiled with -fPIC -fexternal-dynamic-refs and load them
* anywhere in the address space.
*/
#if defined(x86_64_HOST_ARCH) && defined(darwin_HOST_OS)
#define DEFAULT_LINKER_ALWAYS_PIC true
#else
#define DEFAULT_LINKER_ALWAYS_PIC false
#endif
/* See Note [Synchronization of flags and base APIs] */
typedef struct _MISC_FLAGS {
Time tickInterval; /* units: TIME_RESOLUTION */
......@@ -207,7 +196,6 @@ typedef struct _MISC_FLAGS {
bool generate_stack_trace;
bool machineReadable;
bool internalCounters; /* See Note [Internal Counter Stats] */
bool linkerAlwaysPic; /* Assume the object code is always PIC */
StgWord linkerMemBase; /* address to ask the OS for memory
* for the linker, NULL ==> off */
} MISC_FLAGS;
......
......@@ -139,7 +139,6 @@ data MiscFlags = MiscFlags
, generateStackTrace :: Bool
, machineReadable :: Bool
, internalCounters :: Bool
, linkerAlwaysPic :: Bool
, linkerMemBase :: Word
-- ^ address to ask the OS for memory for the linker, 0 ==> off
} deriving ( Show -- ^ @since 4.8.0.0
......@@ -445,8 +444,6 @@ getMiscFlags = do
(#{peek MISC_FLAGS, machineReadable} ptr :: IO CBool))
<*> (toBool <$>
(#{peek MISC_FLAGS, internalCounters} ptr :: IO CBool))
<*> (toBool <$>
(#{peek MISC_FLAGS, linkerAlwaysPic} ptr :: IO CBool))
<*> #{peek MISC_FLAGS, linkerMemBase} ptr
getDebugFlags :: IO DebugFlags
......
......@@ -72,6 +72,10 @@
# 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
......@@ -208,7 +212,9 @@ 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(MAP_32BIT) || DEFAULT_LINKER_ALWAYS_PIC
#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH)
#if defined(MAP_32BIT)
// Try to use MAP_32BIT
#define MMAP_32BIT_BASE_DEFAULT 0
#else
......@@ -217,6 +223,7 @@ 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)
......@@ -489,10 +496,12 @@ 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();
......@@ -1000,30 +1009,29 @@ 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 | tryMap32Bit | fixed | flags));
MAP_PRIVATE | TRY_MAP_32BIT | fixed | flags));
result = mmap(map_addr, size,
PROT_EXEC|PROT_READ|PROT_WRITE,
MAP_PRIVATE|tryMap32Bit|fixed|flags, fd, offset);
MAP_PRIVATE|TRY_MAP_32BIT|fixed|flags, fd, offset);
if (result == MAP_FAILED) {
sysErrorBelch("mmap %" FMT_Word " bytes at %p",(W_)size,map_addr);
......@@ -1031,9 +1039,8 @@ mmap_again:
return NULL;
}
#if defined(x86_64_HOST_ARCH)
if (RtsFlags.MiscFlags.linkerAlwaysPic) {
} else if (mmap_32bit_base != 0) {
#if !defined(ALWAYS_PIC) && defined(x86_64_HOST_ARCH)
if (mmap_32bit_base != 0) {
if (result == map_addr) {
mmap_32bit_base = (StgWord8*)map_addr + size;
} else {
......@@ -1201,10 +1208,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 && !RtsFlags.MiscFlags.linkerAlwaysPic &&
oc->symbol_extras != NULL) {
m32_free(oc->symbol_extras, sizeof(SymbolExtra) * oc->n_symbol_extras);
}
if (!USE_CONTIGUOUS_MMAP && oc->symbol_extras != NULL) {
m32_free(oc->symbol_extras,
sizeof(SymbolExtra) * oc->n_symbol_extras);
}
}
else {
stgFree(oc->symbol_extras);
......@@ -1497,21 +1504,32 @@ HsInt loadOc (ObjectCode* oc)
}
/* Note [loadOc orderings]
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`.
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.
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. If necessary, the actual allocation
happens in `ocGetNames_PEi386` and `ocAllocateSymbolExtras_PEi386` simply
set the correct pointers.
*/
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;
}
#if defined(NEED_SYMBOL_EXTRAS)
# if defined(OBJFORMAT_MACHO)
......@@ -1528,24 +1546,7 @@ 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
......@@ -1829,3 +1830,4 @@ addSection (Section *s, SectionKind kind, SectionAlloc alloc,
start, (void*)((StgWord)start + size),
size, kind ));
}
......@@ -235,7 +235,6 @@ void initRtsFlagsDefaults(void)
RtsFlags.MiscFlags.generate_dump_file = false;
RtsFlags.MiscFlags.machineReadable = false;
RtsFlags.MiscFlags.internalCounters = false;
RtsFlags.MiscFlags.linkerAlwaysPic = DEFAULT_LINKER_ALWAYS_PIC;
RtsFlags.MiscFlags.linkerMemBase = 0;
#if defined(THREADED_RTS)
......@@ -454,11 +453,6 @@ usage_text[] = {
" -e<n> Maximum number of outstanding local sparks (default: 4096)",
#endif
#if defined(x86_64_HOST_ARCH)
#if !DEFAULT_LINKER_ALWAYS_PIC
" -xp Assume that all object files were compiled with -fPIC",
" -fexternal-dynamic-refs and load them anywhere in the address",
" space",
#endif
" -xm Base address to mmap memory in the GHCi linker",
" (hex; must be <80000000)",
#endif
......@@ -1481,11 +1475,6 @@ error = true;
break;
#if defined(x86_64_HOST_ARCH)
case 'p': /* linkerAlwaysPic */
OPTION_UNSAFE;
RtsFlags.MiscFlags.linkerAlwaysPic = true;
break;
case 'm': /* linkerMemBase */
OPTION_UNSAFE;
if (rts_argv[arg][3] != '\0') {
......
......@@ -169,8 +169,6 @@ get_shndx_table(Elf_Ehdr* ehdr)
void
ocInit_ELF(ObjectCode * oc)
{
ocDeinit_ELF(oc);
oc->info = (struct ObjectCodeFormatInfo*)stgCallocBytes(
1, sizeof *oc->info,
"ocInit_Elf(ObjectCodeFormatInfo)");
......@@ -320,7 +318,6 @@ ocDeinit_ELF(ObjectCode * oc)
}
stgFree(oc->info);
oc->info = NULL;
}
}
......@@ -757,7 +754,7 @@ ocGetNames_ELF ( ObjectCode* oc )
start = mem;
mapped_start = mem;
#else
if (USE_CONTIGUOUS_MMAP || RtsFlags.MiscFlags.linkerAlwaysPic) {
if (USE_CONTIGUOUS_MMAP) {
// already mapped.
start = oc->image + offset;
alloc = SECTION_NOMEM;
......@@ -1587,6 +1584,9 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
case COMPAT_R_X86_64_PC32:
{
#if defined(ALWAYS_PIC)
barf("R_X86_64_PC32 relocation, but ALWAYS_PIC.");
#else
StgInt64 off = value - P;
if (off != (Elf64_Sword)off && X86_64_ELF_NONPIC_HACK) {
StgInt64 pltAddress =
......@@ -1603,6 +1603,7 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
}
Elf64_Sword payload = off;
memcpy((void*)P, &payload, sizeof(payload));
#endif
break;
}
......@@ -1615,6 +1616,9 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
case COMPAT_R_X86_64_32:
{
#if defined(ALWAYS_PIC)
barf("R_X86_64_32 relocation, but ALWAYS_PIC.");
#else
if (value != (Elf64_Word)value && X86_64_ELF_NONPIC_HACK) {
StgInt64 pltAddress =
(StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S)
......@@ -1630,11 +1634,15 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
}
Elf64_Word payload = value;
memcpy((void*)P, &payload, sizeof(payload));
#endif
break;
}
case COMPAT_R_X86_64_32S:
{
#if defined(ALWAYS_PIC)
barf("R_X86_64_32S relocation, but ALWAYS_PIC.");
#else
if ((StgInt64)value != (Elf64_Sword)value && X86_64_ELF_NONPIC_HACK) {
StgInt64 pltAddress =
(StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S)
......@@ -1650,6 +1658,7 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
}
Elf64_Sword payload = value;
memcpy((void*)P, &payload, sizeof(payload));
#endif
break;
}
case COMPAT_R_X86_64_REX_GOTPCRELX:
......@@ -1671,6 +1680,9 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
#if defined(dragonfly_HOST_OS)
case COMPAT_R_X86_64_GOTTPOFF:
{
#if defined(ALWAYS_PIC)
barf("R_X86_64_GOTTPOFF relocation, but ALWAYS_PIC.");
#else
/* determine the offset of S to the current thread's tls
area
XXX: Move this to the beginning of function */
......@@ -1688,12 +1700,16 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
}
Elf64_SWord payload = off;
memcpy((void*)P, &payload, sizeof(payload));
#endif
break;
}
#endif
case COMPAT_R_X86_64_PLT32:
{
#if defined(ALWAYS_PIC)
barf("R_X86_64_PLT32 relocation, but ALWAYS_PIC.");
#else
StgInt64 off = value - P;
if (off != (Elf64_Sword)off) {
StgInt64 pltAddress = (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S)
......@@ -1708,6 +1724,7 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
}
Elf64_Sword payload = off;
memcpy((void*)P, &payload, sizeof(payload));
#endif
break;
}
#endif
......
......@@ -99,8 +99,6 @@ bool ocMprotect_MachO( ObjectCode *oc );
void
ocInit_MachO(ObjectCode * oc)
{
ocDeinit_MachO(oc);
oc->info = (struct ObjectCodeFormatInfo*)stgCallocBytes(
1, sizeof *oc->info,
"ocInit_MachO(ObjectCodeFormatInfo)");
......@@ -162,19 +160,16 @@ ocInit_MachO(ObjectCode * oc)
void
ocDeinit_MachO(ObjectCode * oc) {
if (oc->info != NULL) {
if(oc->info->n_macho_symbols > 0) {
stgFree(oc->info->macho_symbols);
}
if(oc->info->n_macho_symbols > 0) {
stgFree(oc->info->macho_symbols);
}
#if defined(aarch64_HOST_ARCH)
freeGot(oc);
for(int i = 0; i < oc->n_sections; i++) {
freeStubs(&oc->sections[i]);
}
#endif
stgFree(oc->info);
oc->info = NULL;
freeGot(oc);
for(int i = 0; i < oc->n_sections; i++) {
freeStubs(&oc->sections[i]);
}
#endif
stgFree(oc->info);
}
static int
......
......@@ -19,12 +19,6 @@
#include "linker/SymbolExtras.h"
#include "linker/M32Alloc.h"
#if defined(OBJFORMAT_ELF)
# include "linker/Elf.h"
#elif defined(OBJFORMAT_MACHO)
# include "linker/MachO.h"
#endif
#include <string.h>
#if RTS_LINKER_USE_MMAP
#include <sys/mman.h>
......@@ -52,24 +46,8 @@
int ocAllocateSymbolExtras( ObjectCode* oc, int count, int first )
{
size_t n;
void* oldImage = oc->image;
if (count > 0) {
if (!RTS_LINKER_USE_MMAP) {
// round up to the nearest 4
int aligned = (oc->fileSize + 3) & ~3;
int misalignment = oc->misalignment;
oc->image -= misalignment;
oc->image = stgReallocBytes( oc->image,
misalignment +
aligned + sizeof (SymbolExtra) * count,
"ocAllocateSymbolExtras" );
oc->image += misalignment;
oc->symbol_extras = (SymbolExtra *) (oc->image + aligned);
} else if (USE_CONTIGUOUS_MMAP || RtsFlags.MiscFlags.linkerAlwaysPic) {
if (RTS_LINKER_USE_MMAP && USE_CONTIGUOUS_MMAP) {
n = roundUpToPage(oc->fileSize);
/* Keep image and symbol_extras contiguous */
......@@ -85,37 +63,42 @@ int ocAllocateSymbolExtras( ObjectCode* oc, int count, int first )
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");
if(mprotect(new, allocated_size, PROT_READ | PROT_EXEC) != 0) {
sysErrorBelch("unable to protect memory");
}
}
else {
oc->symbol_extras = NULL;
return 0;
}
} else {
}
else if( count > 0 ) {
if (RTS_LINKER_USE_MMAP) {
n = roundUpToPage(oc->fileSize);
oc->symbol_extras = m32_alloc(sizeof(SymbolExtra) * count, 8);
if (oc->symbol_extras == NULL) return 0;
}
else {
// round up to the nearest 4
int aligned = (oc->fileSize + 3) & ~3;
int misalignment = oc->misalignment;
oc->image -= misalignment;
oc->image = stgReallocBytes( oc->image,
misalignment +
aligned + sizeof (SymbolExtra) * count,
"ocAllocateSymbolExtras" );
oc->image += misalignment;
oc->symbol_extras = (SymbolExtra *) (oc->image + aligned);
}
}
if (oc->symbol_extras != NULL) {
memset( oc->symbol_extras, 0, sizeof (SymbolExtra) * count );
}
// ObjectCodeFormatInfo contains computed addresses based on offset to
// image, if the address of image changes, we need to invalidate
// the ObjectCodeFormatInfo and recompute it.
if (oc->image != oldImage) {
#if defined(OBJFORMAT_MACHO)
ocInit_MachO( oc );
#endif
#if defined(OBJFORMAT_ELF)
ocInit_ELF( oc );
#endif
}
oc->first_symbol_extra = first;
oc->n_symbol_extras = count;
......
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