On Wednesday, 16 September 2015 at 23:24:29 UTC, bitwise wrote:
I was trying to solve this one myself, but the modifications to
DMD's backend that are needed are out of reach for me right now.
If you're willing to build your own druntime, you may be able
to get by.
I'd prefer a solution that works with existing compilers, but
maybe building a custom LDC is possible if I figure it out.
If I understand correctly, you want to repeatedly load/unload
the same shared library, correct? I ask because druntime for
osx only supports loading a single image at a time:
https://github.com/D-Programming-Language/druntime/blob/1e25749cd01ad08dc08319a3853fbe86356c3e62/src/rt/sections_osx.d#L26
In practive I've found that the D shared libraries I produce can
be dlopen/dlclose any number of times, simultaneous too. Using
both LDC and DMD, don't know why it works.
The thing that doesn't work is the C host program dlopen'ing the
shared library, dlclose it, then dlopen another shared library
written in C.
Anyways, when main() of a D program runs, it calls rt_init()
and rt_term(). If you don't have a D entry point in your
program, you have to retrieve these from your shared lib(which
has druntime statically linked) using dlsym() and call them
yourself.
I don't control the host program. My shared libs do have an
entrypoint, from which I call Runtime.initialize().
I can also use LDC global constructor/destructor to call
Runtime.initialize / Runtime.terminate, but it doesn't work any
better because of the callback.
https://github.com/D-Programming-Language/druntime/blob/478b6c5354470bc70e688c45821eea71b766e70d/src/rt/dmain2.d#L158
Now, initSections() and finiSections() are responsible for
setting up the image. If you look at initSections(), the
function "_dyld_register_func_for_add_image" is the one that
causes the crash, because there is no way to remove the
callback, which will reside in your shared lib.
https://github.com/D-Programming-Language/druntime/blob/1e25749cd01ad08dc08319a3853fbe86356c3e62/src/rt/sections_osx.d#L76
So what happens is, when you call
_dyld_register_func_for_add_image, dyld will call your callback
for every shared-library/image(including the main application's
image) that is currently loaded. However, you can skip the
callback and just call "sections_osx_onAddImage" yourself.
You would have to add something like this to sections_osx.d,
and call it instead of adding the callback:
void callOnAddImage()
{
// dladdr() should give you information about the
// shared lib in which the symbol you pass resides.
// Passing the address of this function should work.
Dl_info info;
int ret = dladdr(cast(void*)&callOnAddImage, &info);
assert(ret);
// "dli_fbase" is actually a pointer to
// the mach_header for the shared library.
// once you have the mach_header, you can
// also retrieve the image slide, and finally
// call sections_osx_onAddImage().
mach_header* header = cast(mach_header*)info.dli_fbase;
intptr_t slide = _dyld_get_image_slide(header);
sections_osx_onAddImage(header, slide);
}
Now, if you look at finiSections(), it seems to be incomplete.
There is nothing like sections_osx_onRemoveImage, so you'll
have to complete it to make sure the library is unloaded
correctly:
https://github.com/D-Programming-Language/druntime/blob/1e25749cd01ad08dc08319a3853fbe86356c3e62/src/rt/sections_osx.d#L83
You'll may have to make other mods here and there to get this
working correctly, but this is the bulk of it.
Bit
Thanks for your answer. This is really helpful, though I don't
understand the first thing about what images, headers and
sections are in this context.