Curious Windows GHCi linker behaviour .o vs. .dll

Herbert Valerio Riedel hvriedel at gmail.com
Sat Oct 11 13:24:02 UTC 2014


Hello *,

I assume this is a well known issue to MSYS2/Windows developers, so I
hope somebody may be able to provide more insight for me to better
understand the underlying problem of

  https://github.com/haskell/time/issues/2


So the prototype for tzset() is simply

    void tzset(void);

and it's defined in `msvcrt.dll` as far as I can tell; 
Consider the following trivial program:

    module Main where
     
    foreign import ccall unsafe "time.h tzset" c_tzset :: IO ()
     
    main :: IO()
    main = c_tzset

When compiled with GHC 7.8.3, the resulting executable works and has the
following tzset-symbols:

    $ nm tz.o | grep tzset
                     U tzset

    $ nm tz.exe  | grep tzset
    000000000050e408 I __imp_tzset
    00000000004afc40 T tzset

However, when loaded into GHCi, the RTS linker fails to find `tzset`:

    $ ghci tz.hs
    WARNING: GHCi invoked via 'ghci.exe' in *nix-like shells (cygwin-bash, in particular)
             doesn't handle Ctrl-C well; use the 'ghcii.sh' shell wrapper instead
    GHCi, version 7.8.3: http://www.haskell.org/ghc/  :? for help
    Loading package ghc-prim ... linking ... done.
    Loading package integer-gmp ... linking ... done.
    Loading package base ... linking ... done.
    [1 of 1] Compiling Main             ( tz.hs, interpreted )
     
    ByteCodeLink: can't find label
    During interactive linking, GHCi couldn't find the following symbol:
      tzset
    ...

However, when I prefix a `_` to the symbol-name in the FFI import, i.e.

    foreign import ccall unsafe "time.h tzset" c_tzset :: IO ()

Now, GHCi happily loads the module and is apparently able to resolve the
`tzset` symbol:

    $ ghci tz.hs
    WARNING: GHCi invoked via 'ghci.exe' in *nix-like shells (cygwin-bash, in particular)
             doesn't handle Ctrl-C well; use the 'ghcii.sh' shell wrapper instead
    GHCi, version 7.8.3: http://www.haskell.org/ghc/  :? for help
    Loading package ghc-prim ... linking ... done.
    Loading package integer-gmp ... linking ... done.
    Loading package base ... linking ... done.
    [1 of 1] Compiling Main             ( tz.hs, interpreted )
    Ok, modules loaded: Main.
    *Main> 

Moreover, compiling and running the program still works, and the
additional underscore is visible in `nm` as well:

    $ nm tz.o | grep tzset
                     U _tzset

    $ nm tz.exe | grep tzset
    000000000050e558 I __imp__tzset
    00000000004b8050 T _tzset


What's going on here? Why does one need to add an artificial underscore
to FFI imported symbols for GHCi to resolve symbols? Is this a bug?


Cheers,
  hvr


More information about the ghc-devs mailing list