diff options
author | Ben Gamari <ben@smart-cactus.org> | 2022-02-04 08:53:27 -0500 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2022-04-06 16:25:25 -0400 |
commit | e689e9d5d058dbe05890038c28abdf3301679d7b (patch) | |
tree | cc45413a703faf8aecaa54ce1993b6f7de6ff62c /rts | |
parent | d286a55caebca8a4e5e73bbfeeb766e333271a09 (diff) | |
download | haskell-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.h | 1 | ||||
-rw-r--r-- | rts/RtsSymbols.c | 12 | ||||
-rw-r--r-- | rts/linker/PEi386.c | 30 |
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)) { |