On Wednesday, 16 September 2015 at 22:29:46 UTC, ponce wrote:
Context: On OSX, a C program can load a D shared library but once unloaded the next dlopen will crash, jumping into a callback that doesn't exist anymore.

I've filed it here: https://issues.dlang.org/show_bug.cgi?id=15060


It looks like this was known and discussed several times already:
http://forum.dlang.org/post/[email protected] (2015)
https://github.com/D-Programming-Language/druntime/pull/228 (2012)


Any idea to work-around this problem would be awesome.

I'm not looking for something correct, future-proof, or pretty. Any shit that still stick to the wall will do. Anything!

The only case I need to support is: C host, D shared library, with runtime statically linked.

Please help!

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.

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

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.

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

Reply via email to