[GHC] #12031: GHCi segfaults on Windows when compiling C code using extern-declared variable
GHC
ghc-devs at haskell.org
Tue Jun 7 13:55:04 UTC 2016
#12031: GHCi segfaults on Windows when compiling C code using extern-declared
variable
--------------------------------+----------------------------------------
Reporter: RyanGlScott | Owner: Phyx-
Type: bug | Status: new
Priority: normal | Milestone:
Component: GHCi | Version: 8.0.1
Resolution: | Keywords:
Operating System: Windows | Architecture: Unknown/Multiple
Type of failure: GHCi crash | Test Case:
Blocked By: | Blocking:
Related Tickets: | Differential Rev(s):
Wiki Page: |
--------------------------------+----------------------------------------
Changes (by Phyx-):
* owner: => Phyx-
Comment:
Thanks for the simplified example @RyanGlScott. It made it a lot easier to
find.
This seems like it has to do with MingW-w64's pseudo-relocation features.
The references to the `foo` extern value seems to go through a `.refptr`
reference.
The values to jump to are contained in their own `$rdata` section such as
{{{
Disassembly of section .rdata$.refptr.foo:
0000000000000000 <.refptr.foo>:
...
0: R_X86_64_64 foo
}}}
Which contains the address of `foo`. It seems that this is done to take
advantage of the
full 48-bit address space for x64 Windows. This because the instruction
relocations are done
in 32-bit space. e.g. using R_X86_64_PC32.
Looking at the dissassembly of `baz.c` you see that the direct lookup of
`foo` has been replaced.
{{{
Disassembly of section .text:
0000000000000000 <baz>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 83 ec 20 sub $0x20,%rsp
8: 48 8b 05 00 00 00 00 mov 0x0(%rip),%rax # f <baz+0xf>
b: R_X86_64_PC32 .refptr.foo
f: 8b 00 mov (%rax),%eax
11: 89 c2 mov %eax,%edx
}}}
The runtime linker doesn't know about this and happily just returns the
address of `.refptr.foo`
In bar we set the value of `foo` directly since it's a local defined in
the `.bss` of that object file.
So there the runtime linker does the correct thing.
What happens during runtime:
{{{
1: x/10i $pc
=> 0xf920209: movl $0x1,-0xeca63(%rip) # 0xf8337b0
0xf920213: callq 0xf930248
}}}
So `foo` is at `0xf8337b0`
{{{
1: x/10i $pc
=> 0xf930248: push %rbp
0xf930249: mov %rsp,%rbp
0xf93024c: sub $0x20,%rsp
0xf930250: mov 0x292(%rip),%rax # 0xf9304e9
0xf930257: mov (%rax),%eax
0xf930259: mov %eax,%edx
0xf93025b: lea 0x26(%rip),%rcx # 0xf930288
0xf930262: callq 0xf930960
0xf930267: mov -0xfcfde(%rip),%rax # 0xf833290
0xf93026e: callq *%rax
}}}
`$rax` here contains address of `.refptr.foo` which is at `0xf9304e9`.
Essentially de-referencing `*$rax` gets you the address of `foo`, de-
ferencing `**$rax` gets you the value of foo.
{{{
(gdb) p/x 0xf9304e9
$1 = 0xf9304e9
(gdb) p/x *0xf9304e9
$2 = 0xf8337b0
(gdb) p/x **0xf9304e9
$3 = 0x1
}}}
So when we lookup a `.refptr.foo` we can do one of two things,
1) Drop the `.refptr.` prefix and lookup `foo` directly.
2) When doing a `.refptr.`, de-reference the value and return that one
instead.
As for why it's working sporadically.. I have no idea..
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/12031#comment:2>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list