Dynamic linking again
Duncan Coutts
duncan@coutts.uklinux.net
Mon, 2 Sep 2002 14:13:21 +0100
On Mon, 2 Sep 2002 11:31:27 +0100
"Simon Marlow" <simonmar@microsoft.com> wrote:
>
> > So here's another idea. ghc's linker provides (via the ffi) a command
> > addDLL to load dynamic libraries. It uses dlopen on unix and
> > LoadLibrary on win32.
> >
> > Now, with dlopen if you pass it NULL rather than the filename of a
> > library it will give you back a handle to itself - the program that
> > called it. If you've linked your program with the right incantations
> > this gives you access to all the symbols in the main program.
>
> Yes, we already use dlopen() with NULL to get symbols from other shared
> libraries, so you can refer to things like printf() from libc.
I noticed this just after posting, so you don't even need to do call addDLL,
just doing initLinker is sufficient.
> I didn't know about -export-dynamic: yes, it looks like that would do
> exactly the right thing. The linker might not even need any
> modification for this to work, because we already fall back to using
> dlsym() for a symbol that the linker can't find in its own symbol table.
> [... I've just tried a simple example using -export-dynamic, and it does
> indeed work as advertised... ]
In fact it all works quite nicely, I've got a test program with a little
plugin module that refers back to the main program. When the main
program is linked with -optl-export-dynamic the plugin can be loaded up
and all symbols resolve correctly. I still had to load copies of the
base packages since the plugin .o still refers to symbols not in the
main executalbe. (More on that in a moment)
And yes indeed, it works with a vanilla ghc-5.04
> To like the whole of the base package into the binary, you can either
> use --whole-archive with libHSbase.a as suggested by Alastair, or link
> in HSbase.o. Similarly for the haskell98 package.
I got lots of linking errors about duplicate symbols doing using
--whole-archive for the standard packages. Perhaps someone who knows a
bit more about linking could advise me.
It works linking in HSbase.o however. Here's the output of the test
program. It loads the .o file of a plugin module that imports things
from the main program:
[duncan@dunky dlink]$ ./TestDLink
GHC dynamic loading test program
c_loadObj pluginObj returned 1
c_resolveObjs returned 1
lookup symbol:
> TestObj_foo_closure
symbol is present
where "TestObj_foo_closure" is a symbol corresponding to my function
"foo" defined to be a function imported from the main program. Note here
that I am not loading a copy of the base package at runtime, it is
resolving against the copy already in the main executable immage. Of
course the main program's binary is now much larger ~5mb stripped vs
350k. Note that the program can be striped because the symbls are in a
special dynamic export ELF section so do not get stripped.
I'm having a problem using just -package flags. I get unresloved
symbols. I'm currently doing this:
ghc -optl-export-dynamic -ldl -L/usr/lib/ghc-5.04/ -lHSrts -lHSlang \
TestDLink.o -o TestDLink
since doing
ghc -optl-export-dynamic -ldl -package rst -package lang \
TestDLink.o -o TestDLink
gives:
/usr/lib/ghc-5.04/libHSrts.a(RtsAPIDeprec.o): In function `rts_mkAddr':
RtsAPIDeprec.o(.text+0x14): undefined reference to `Addr_Azh_con_info'
/usr/lib/ghc-5.04/libHSrts.a(RtsAPIDeprec.o): In function `rts_getAddr':
RtsAPIDeprec.o(.text+0x2d): undefined reference to `Addr_Azh_con_info'
RtsAPIDeprec.o(.text+0x35): undefined reference to `Addr_Azh_static_info'
collect2: ld returned 1 exit status
the flag -ldl is required to aviod link errors about dlopen() and friends.
So generally quite sucessful. I should probably come up with some
tutorial / documentation on doing plugins with ghc.
Duncan