diff options
author | Tamar Christina <tamar@zhox.com> | 2016-06-11 10:18:19 +0200 |
---|---|---|
committer | Tamar Christina <tamar@zhox.com> | 2016-06-12 13:43:32 +0200 |
commit | b40e1b4c6746bdc34e6a53548a3925d309201c4d (patch) | |
tree | 8db58488f701c2dc944714406ebf5fc9a4bbcf6f /testsuite/tests/rts/T12031 | |
parent | 913086797af8060808973e8f6a11a3702afffe14 (diff) | |
download | haskell-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 'testsuite/tests/rts/T12031')
-rw-r--r-- | testsuite/tests/rts/T12031/ExternBug.hs | 9 | ||||
-rw-r--r-- | testsuite/tests/rts/T12031/Makefile | 8 | ||||
-rw-r--r-- | testsuite/tests/rts/T12031/T12031.stdout | 1 | ||||
-rw-r--r-- | testsuite/tests/rts/T12031/all.T | 4 | ||||
-rw-r--r-- | testsuite/tests/rts/T12031/bar.c | 11 | ||||
-rw-r--r-- | testsuite/tests/rts/T12031/baz.c | 9 | ||||
-rw-r--r-- | testsuite/tests/rts/T12031/foo.h | 11 |
7 files changed, 53 insertions, 0 deletions
diff --git a/testsuite/tests/rts/T12031/ExternBug.hs b/testsuite/tests/rts/T12031/ExternBug.hs new file mode 100644 index 0000000000..5c28aede00 --- /dev/null +++ b/testsuite/tests/rts/T12031/ExternBug.hs @@ -0,0 +1,9 @@ +-- Copyright (c) 2016, Ryan Scott +-- ExternBug.hs +{-# LANGUAGE ForeignFunctionInterface #-} +module ExternBug (bar) where + +{-# INCLUDE foo.h #-} + +foreign import ccall "bar" + bar :: IO () diff --git a/testsuite/tests/rts/T12031/Makefile b/testsuite/tests/rts/T12031/Makefile new file mode 100644 index 0000000000..0a9420692a --- /dev/null +++ b/testsuite/tests/rts/T12031/Makefile @@ -0,0 +1,8 @@ +TOP=../../.. +include $(TOP)/mk/boilerplate.mk +include $(TOP)/mk/test.mk + +T12031: + '$(TEST_HC)' -c bar.c -o bar.o + '$(TEST_HC)' -c baz.c -o baz.o + echo bar | '$(TEST_HC)' $(TEST_HC_OPTS_INTERACTIVE) bar.o baz.o ExternBug.hs diff --git a/testsuite/tests/rts/T12031/T12031.stdout b/testsuite/tests/rts/T12031/T12031.stdout new file mode 100644 index 0000000000..e5cc126783 --- /dev/null +++ b/testsuite/tests/rts/T12031/T12031.stdout @@ -0,0 +1 @@ +The value of foo is 1 diff --git a/testsuite/tests/rts/T12031/all.T b/testsuite/tests/rts/T12031/all.T new file mode 100644 index 0000000000..b051514109 --- /dev/null +++ b/testsuite/tests/rts/T12031/all.T @@ -0,0 +1,4 @@ +test('T12031', [ extra_clean(['bar.o', 'baz.o', 'ExternBug.o']) + , extra_files(['bar.c', 'baz.c', 'ExternBug.hs', 'foo.h']) + ], + run_command, ['$MAKE -s --no-print-directory T12031']) diff --git a/testsuite/tests/rts/T12031/bar.c b/testsuite/tests/rts/T12031/bar.c new file mode 100644 index 0000000000..257cc198f4 --- /dev/null +++ b/testsuite/tests/rts/T12031/bar.c @@ -0,0 +1,11 @@ +// Copyright (c) 2016, Ryan Scott +// bar.c +#include "foo.h" + +int foo = 0; + +void bar(void) { + foo = 1; + + baz(); +} diff --git a/testsuite/tests/rts/T12031/baz.c b/testsuite/tests/rts/T12031/baz.c new file mode 100644 index 0000000000..d710148736 --- /dev/null +++ b/testsuite/tests/rts/T12031/baz.c @@ -0,0 +1,9 @@ +// Copyright (c) 2016, Ryan Scott +// baz.c +#include "foo.h" +#include <stdio.h> + +void baz(void) { + printf("The value of foo is %d\n", foo); // Segfaults on this line + fflush(stdout); +} diff --git a/testsuite/tests/rts/T12031/foo.h b/testsuite/tests/rts/T12031/foo.h new file mode 100644 index 0000000000..d3ca4aad2d --- /dev/null +++ b/testsuite/tests/rts/T12031/foo.h @@ -0,0 +1,11 @@ +// Copyright (c) 2016, Ryan Scott +// foo.h +#ifndef FOO_H +#define FOO_H + +extern int foo; + +void bar(void); +void baz(void); + +#endif |