summaryrefslogtreecommitdiff
path: root/rts/LinkerInternals.h
diff options
context:
space:
mode:
authorTamar Christina <tamar@zhox.com>2016-06-11 10:18:19 +0200
committerTamar Christina <tamar@zhox.com>2016-06-12 13:43:32 +0200
commitb40e1b4c6746bdc34e6a53548a3925d309201c4d (patch)
tree8db58488f701c2dc944714406ebf5fc9a4bbcf6f /rts/LinkerInternals.h
parent913086797af8060808973e8f6a11a3702afffe14 (diff)
downloadhaskell-b40e1b4c6746bdc34e6a53548a3925d309201c4d.tar.gz
Fix incorrect calculated relocations on Windows x86_64
Summary: See #12031 for analysis, but essentially what happens is: To sum up the issue, the reason this seems to go wrong is because of how we initialize the `.bss` section for Windows in the runtime linker. The first issue is where we calculate the zero space for the section: ``` zspace = stgCallocBytes(1, bss_sz, "ocGetNames_PEi386(anonymous bss)"); sectab_i->PointerToRawData = ((UChar*)zspace) - ((UChar*)(oc->image)); ``` Where ``` UInt32 PointerToRawData; ``` This means we're stuffing a `64-bit` value into a `32-bit` one. Also `zspace` can be larger than `oc->image`. In which case it'll overflow and then get truncated in the cast. The address of a value in the `.bss` section is then calculated as: ``` addr = ((UChar*)(oc->image)) + (sectabent->PointerToRawData + symtab_i->Value); ``` If it does truncate then this calculation won't be correct (which is what is happening). We then later use the value of `addr` as the `S` (Symbol) value for the relocations ``` S = (size_t) lookupSymbol_( (char*)symbol ); ``` Now the majority of the relocations are `R_X86_64_PC32` etc. e.g. They are guaranteed to fit in a `32-bit` value. The `R_X86_64_64` introduced for these pseudo-relocations so they can use the full `48-bit` addressing space isn't as lucky. As for why it sometimes work has to do on whether the value is truncated or not. `PointerToRawData` can't be changed because it's size is fixed by the PE specification. Instead just like with the other platforms, we now use `section` on Windows as well. This gives us a `start` parameter of type `void*` which solves the issue. This refactors the code to use `section.start` and to fix the issues. Test Plan: ./validate and new test added T12031 Reviewers: RyanGlScott, erikd, bgamari, austin, simonmar Reviewed By: simonmar Subscribers: thomie, #ghc_windows_task_force Differential Revision: https://phabricator.haskell.org/D2316 GHC Trac Issues: #12031, #11317
Diffstat (limited to 'rts/LinkerInternals.h')
-rw-r--r--rts/LinkerInternals.h4
1 files changed, 2 insertions, 2 deletions
diff --git a/rts/LinkerInternals.h b/rts/LinkerInternals.h
index 815180c757..5686863cbb 100644
--- a/rts/LinkerInternals.h
+++ b/rts/LinkerInternals.h
@@ -43,8 +43,8 @@ typedef
typedef
struct _Section {
- void* start; /* actual start of section in memory */
- StgWord size; /* actual size of section in memory */
+ void* start; /* actual start of section in memory */
+ StgWord size; /* actual size of section in memory */
SectionKind kind;
SectionAlloc alloc;