[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