summaryrefslogtreecommitdiff
path: root/rts
diff options
context:
space:
mode:
authorBen Gamari <ben@smart-cactus.org>2022-02-04 08:53:27 -0500
committerBen Gamari <ben@smart-cactus.org>2022-04-06 16:25:25 -0400
commite689e9d5d058dbe05890038c28abdf3301679d7b (patch)
treecc45413a703faf8aecaa54ce1993b6f7de6ff62c /rts
parentd286a55caebca8a4e5e73bbfeeb766e333271a09 (diff)
downloadhaskell-e689e9d5d058dbe05890038c28abdf3301679d7b.tar.gz
rts/PEi386: Fix relocation overflow behavior
This fixes handling of overflowed relocations on PEi386 targets: * Refuse to create jump islands for relocations of data symbols * Correctly handle the `__imp___acrt_iob_func` symbol, which is an new type of symbol: `SYM_TYPE_INDIRECT_DATA`
Diffstat (limited to 'rts')
-rw-r--r--rts/LinkerInternals.h1
-rw-r--r--rts/RtsSymbols.c12
-rw-r--r--rts/linker/PEi386.c30
3 files changed, 27 insertions, 16 deletions
diff --git a/rts/LinkerInternals.h b/rts/LinkerInternals.h
index 61c054363f..b1cd3a8a9a 100644
--- a/rts/LinkerInternals.h
+++ b/rts/LinkerInternals.h
@@ -49,6 +49,7 @@ typedef struct _Section Section;
typedef enum _SymType {
SYM_TYPE_CODE, /* the symbol is a function and can be relocated via a jump island */
SYM_TYPE_DATA, /* the symbol is data */
+ SYM_TYPE_INDIRECT_DATA, /* see Note [Relocating iob_func on Windows] */
} SymType;
diff --git a/rts/RtsSymbols.c b/rts/RtsSymbols.c
index 400e3122bc..b4e6da9470 100644
--- a/rts/RtsSymbols.c
+++ b/rts/RtsSymbols.c
@@ -175,9 +175,9 @@ extern char **environ;
/* ^^ Need to figure out why this is needed. */ \
/* See Note [_iob_func symbol] */ \
RTS_WIN64_ONLY(SymI_HasProto_redirect( \
- __imp___acrt_iob_func, __rts_iob_func, STRENGTH_WEAK)) \
+ __imp___acrt_iob_func, __rts_iob_func, STRENGTH_WEAK, SYM_TYPE_INDIRECT_DATA)) \
RTS_WIN32_ONLY(SymI_HasProto_redirect( \
- __imp____acrt_iob_func, __rts_iob_func, STRENGTH_WEAK)) \
+ __imp____acrt_iob_func, __rts_iob_func, STRENGTH_WEAK, SYM_TYPE_INDIRECT_DATA)) \
SymI_HasProto(__mingw_vsnwprintf) \
/* ^^ Need to figure out why this is needed. */ \
SymI_HasProto(__mingw_vfprintf) \
@@ -1072,7 +1072,7 @@ extern char **environ;
// Symbols defined by libc
#define RTS_LIBC_SYMBOLS \
- SymI_HasProto_redirect(atexit, atexit, STRENGTH_STRONG) /* See Note [Strong symbols] */ \
+ SymI_HasProto_redirect(atexit, atexit, STRENGTH_STRONG, CODE_TYPE_CODE) /* See Note [Strong symbols] */ \
SymI_HasProto(environ)
#if !defined(DYNAMIC) && defined(linux_HOST_OS)
@@ -1104,7 +1104,7 @@ extern char **environ;
#define SymE_HasProto(vvv) SymI_HasProto(vvv)
#endif
#define SymI_HasProto(vvv) /**/
-#define SymI_HasProto_redirect(vvv,xxx,strength) /**/
+#define SymI_HasProto_redirect(vvv,xxx,strength,ty) /**/
#define SymI_HasProto_deprecated(vvv) /**/
RTS_SYMBOLS
RTS_RET_SYMBOLS
@@ -1142,9 +1142,9 @@ RTS_LIBFFI_SYMBOLS
// SymI_HasProto_redirect allows us to redirect references to one symbol to
// another symbol. See newCAF/newRetainedCAF/newGCdCAF for an example.
-#define SymI_HasProto_redirect(vvv,xxx,strength) \
+#define SymI_HasProto_redirect(vvv,xxx,strength,ty) \
{ MAYBE_LEADING_UNDERSCORE_STR(#vvv), \
- (void*)(&(xxx)), strength, SYM_TYPE_CODE },
+ (void*)(&(xxx)), strength, ty },
// SymI_HasProto_deprecated allows us to redirect references from their deprecated
// names to the undeprecated ones. e.g. access -> _access.
diff --git a/rts/linker/PEi386.c b/rts/linker/PEi386.c
index 00c28a959d..b8bcc8abec 100644
--- a/rts/linker/PEi386.c
+++ b/rts/linker/PEi386.c
@@ -1780,16 +1780,24 @@ ocAllocateExtras_PEi386 ( ObjectCode* oc )
}
static size_t
-makeSymbolExtra_PEi386( ObjectCode* oc, uint64_t index STG_UNUSED, size_t s, char* symbol STG_UNUSED )
+makeSymbolExtra_PEi386( ObjectCode* oc, uint64_t index STG_UNUSED, size_t s, char* symbol STG_UNUSED, SymType type )
{
SymbolExtra *extra = m32_alloc(oc->rx_m32, sizeof(SymbolExtra), 8);
- // jmp *-14(%rip)
- static uint8_t jmp[] = { 0xFF, 0x25, 0xF2, 0xFF, 0xFF, 0xFF };
- extra->addr = (uint64_t)s;
- memcpy(extra->jumpIsland, jmp, 6);
-
- return (size_t)extra->jumpIsland;
+ if (type == SYM_TYPE_CODE) {
+ // jmp *-14(%rip)
+ extra->addr = (uint64_t)s;
+ static uint8_t jmp[] = { 0xFF, 0x25, 0xF2, 0xFF, 0xFF, 0xFF };
+ memcpy(extra->jumpIsland, jmp, 6);
+ return (size_t)&extra->jumpIsland;
+ } else if (type == SYM_TYPE_INDIRECT_DATA) {
+ void *v = *(void**) s;
+ extra->addr = (uint64_t)v;
+ return (size_t)&extra->addr;
+ } else {
+ extra->addr = (uint64_t)s;
+ return (size_t)&extra->addr;
+ }
}
void ocProtectExtras(ObjectCode* oc STG_UNUSED) { }
@@ -1842,6 +1850,8 @@ ocResolve_PEi386 ( ObjectCode* oc )
uint64_t symIndex = reloc->SymbolTableIndex;
sym = &oc->info->symbols[symIndex];
+ SymType sym_type;
+
IF_DEBUG(linker_verbose,
debugBelch(
"reloc sec %2d num %3d: type 0x%-4x "
@@ -1859,7 +1869,7 @@ ocResolve_PEi386 ( ObjectCode* oc )
} else {
copyName ( getSymShortName (info, sym), oc, symbol,
sizeof(symbol)-1 );
- S = (size_t) lookupDependentSymbol( (char*)symbol, oc, NULL );
+ S = (size_t) lookupDependentSymbol( (char*)symbol, oc, &sym_type );
if ((void*)S == NULL) {
errorBelch(" | %" PATH_FMT ": unknown symbol `%s'", oc->fileName, symbol);
releaseOcInfo (oc);
@@ -1927,7 +1937,7 @@ ocResolve_PEi386 ( ObjectCode* oc )
if (((int64_t) v > (int64_t) INT32_MAX) || ((int64_t) v < (int64_t) INT32_MIN)) {
copyName (getSymShortName (info, sym), oc,
symbol, sizeof(symbol)-1);
- S = makeSymbolExtra_PEi386(oc, symIndex, S, (char *)symbol);
+ S = makeSymbolExtra_PEi386(oc, symIndex, S, (char *)symbol, sym_type);
/* And retry */
v = S + A;
@@ -1951,7 +1961,7 @@ ocResolve_PEi386 ( ObjectCode* oc )
/* Make the trampoline then */
copyName (getSymShortName (info, sym),
oc, symbol, sizeof(symbol)-1);
- S = makeSymbolExtra_PEi386(oc, symIndex, S, (char *)symbol);
+ S = makeSymbolExtra_PEi386(oc, symIndex, S, (char *)symbol, sym_type);
/* And retry */
v = S + (int32_t)A - ((intptr_t)pP) - 4;
if ((v > (int64_t) INT32_MAX) || (v < (int64_t) INT32_MIN)) {