Dynamic Linking help

lonetiger at gmail.com lonetiger at gmail.com
Fri Oct 28 17:41:29 UTC 2016

Hi Ben,

Thanks for the reply!

> > Hi *,
> >
> > I’ve been working the past 4 or so months on reviving dynamic linking
> > support for Windows in a way that has the most chance of working.
> >
> > My first patch in the series is up on Phabricator and with this patch
> > dynamic linking work again, but only for the threaded RTS.
> >
> Thanks for all of your work on this, Tamar!

Home stretch :)

> > The reason for this is because the core libraries that get distributed
> > with GHC get compiled with -threaded and shared libraries on Windows
> > can’t have dangling symbols.
> >
> Let me make sure we are on the same page here: By "dangling symbols" do
> you just mean symbols that the linker did not find a definition for at
> link time (e.g. as is the case with libHSrts symbols when we link
> libHSbase)?

Yes, indeed.

> > In any case, I’m at the point now where I need to be able to delay the
> > selection of the runtime library till the final link. E.g. when the
> > exe or dll is made. The problem however is that when linked normally,
> > dependencies are satisfied by the Windows loader, before the program
> > is run. One way I could do this is with Window’s equivalent to SONAME.
> > Unfortunately this only works with SxS Assemblies, and I’ll need Admin
> > rights to be able to register the shared libraries.
> >
> Hmm, why? I thought recent Windows releases had a notion of "user local"
> installation, no? From what little I have heard it sounds like SxS
> assemblies is the right solution here.

Yes, so to be clear, SxS absolutely solve this problem. For final installs.
The majority of the issue is that the testsuite won't have the assemblies in
the SxS cache.

There *is* a sort of RPATH equivalent for SxS that can be used here, it however
has two problems:
1) Even though the API has no such limit, the implementation in the Windows loader
   limits it per application to 5 entries. Obviously this won't be enough. 
   So this is absolutely another option (maybe even preferable now that I think about it
   since it require almost no code change, mostly some build system changes.).
   Can do either one of two things:
   a) Copy all dll's to the lib folder when they're compiled instead of leaving them in place and
      add a single SxS search entry to find them.
   b) Turn of SxS in the testsuite for any Assemblies not the RTS, and add the inplace RTS directory to
      the SxS search path. Since it's only the RTS that's an issue.
2) The other problem is that the paths specified have to be relative to the application.
   (Of the top of my head) It doesn't support absolute paths. Which means I can't have GHC generate the entry because I have no idea where the testsuite intends to run the binary.
   One way around this is to have the testsuite generate the needed config file. That should be do-able.
I'll investigate this method first. I had discarded it for some reason before but now can't remember...

> > This is a problem for running tests in the testsuite using the inplace GHC.
> >
> > Typically on Windows the way you would do this is by delay loading the
> > dll. This allows me to write some code on startup and manually load
> > the runtime dll. The Windows loader would then just use the loaded
> > dll. Unfortunately delay loading does not support const extern data.
> > Such as const extern RtsConfig defaultRtsConfig;
> >
> Silly Windows.

Yeah, unfortunately this is because this isn't done by any OS functions. Lazy loading is purely something
implemented by linkers on Windows and the appropriate runtimes. In essense it just creates a stub that replaces all functions, which first checks if the dll is loaded, if not load it and then call the real function. Which is why it only works for functions.

> > The RTS/GHC is full of such usage so it won’t be easy to change.
> > Though I’d only have to change those exposed by Rts.h.
> >
> > So I have two options:
> > 1) Replace all const externs with a function call. This would work,
> >    but isn’t ideal because it would break if someone in the future
> >    adds a new data entry instead of a function. And we have an extra
> >    function call everywhere.
> Right, I'm really not a fan of this option. Crippling the RTS's use of C
> on account of arbitrary limitations of the Windows dynamic linker
> doesn't seem very appealing.

I was not a fan of this either. Would imagine I would be chased around with flaming pitchforks were I to do this..

> > 2) I could do some hacks on the Windows side, e.g. compile the program
> > to a shared library, embed the shared library inside the exe and on
> > startup after loading the propert rts, load the DLL from (mmapped)
> > memory and run the code.
> This sounds like it would get the job done, although it certainly adds
> complexity. Do you have any intuition for how much work it would be to
> implement this?

We sorta already do 80% of this. For Windows when making a dynamic version of GHC, the ghc-stage2.exe is a 
very thin shell, who's only purpose is to load the right libraries and change the search path to include the lib folder. The actual code is in a dll named e.g. ghc-stage2.exe.dll. The change needed would be to embed this dll into the exe (which is trivially done), and then load it from memory. This would require some work but there are enough wrapper code out there with appropriate licenses that we can use to accomplish this. Or at least get a running head start.

> Cheers,
> - Ben
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-devs/attachments/20161028/bbf42ad3/attachment.html>

More information about the ghc-devs mailing list