51

When loading shared libraries in Windows, LoadLibrary() call causes DllMain in library to execute for each new process and thread library attaches to, and for each process and thread library deattaches from.

Is there similar mechanism for Mac OS X, Linux and possibly other POSIX-compatible OSs?

P̲̳x͓L̳
  • 3,615
  • 3
  • 29
  • 37
toriningen
  • 7,196
  • 3
  • 46
  • 68

4 Answers4

65

You can define an on-load function for a linux library using the .init mechanism. This is the same as specifying the load-time entry point for a binary (e.g. using something other than main as the entry point for a program).

When linking using ld directly you use the:

-init <function name>

or if you're using cc/gcc to link, you use:

-Wl,-init,<function name>

This is at it's most simple level.

Edit For destructors/finalizers, you use the .fini mechanism. This operates in the same manner as the init option, and you use:

-fini <function name>

when invoking ld. Availability is limited to the -init option on the Mac OSX platform.

You should also be able to use the __attribute__((constructor)) syntax for gcc:

static void con() __attribute__((constructor));

void con() {
    printf("I'm a constructor\n");
}

Which is probably a more portable way rather than screwing with the linker options. All constructors should be invoked at load-time, but don't depend on the order of their initialization, that leads to insanity and unreproducible bugs that cost time and effort to debug.

Edit 2 The use of the __attribute__((constructor))/__attribute__((destructor)) semantic is the most preferable mechanism for the C/C++ programming language.

For the D programming language you should really use the static module constructor/destructor:

static this() {
    printf("static this for mymodule\n");
}
static ~this() {
    printf("static ~this for mymodule\n");
}

Or the static class constructor:

class Foo {
    static this() {
        printf("static this for Foo\n");
    }
}

This is strongly hinted at in the writing win32 DLLS and in the language specification relating to static constructors/destructors.

Edit 3 You will need to link in a .o that exports constructor/destructor routines, that will allow the use of the static initializers. As all it should do is call Runtime.initialize(), this actually invokes all the static constructors/destructors in the D code.

Stub d code for the initializer (in a file called myshared.d):

import core.runtime;

extern (C) {
    void attach();
    void detach();
}

export void attach() {
    Runtime.initialize();
}

export void detach() {
    Runtime.terminate();
}

Create the .o for this stub:

 dmd -m32 -c myshared.d

Check the names of the attach/detach functions:

nm myshared.o

Shows (among other output):

0000001c S _D8myshared6attachFZv
00000034 S _D8myshared6detachFZv

sample .c code for invoking this (called export.c in this case), we reference the names of the exported routines from the my shared.o file:

extern void D8myshared6attachFZv(void);
extern void D8myshared6detachFZv(void);

void __attach(void) __attribute__((constructor));
void __detach(void) __attribute__((destructor));

void __attach(void)
{
    D8myshared6attachFZv();
}

void __detach(void)
{
    D8myshared6detachFZv();
}

Note that the extern void references need to use the mangled name of the exported function. These must match or the code will not link.

compile the C code using:

gcc -m32 -c export.c

link the .c.o and the .d.o files together using:

cc -o libmyshared.dylib -m32 -shared myshared.o export.o -lphobos2

Assuming that the phobos2 library is in your standard linker search path. The smatterings of -m32 options for the compiler and linker are because the version of the D compiler that I built locally only supported 32bit.

This produces a .dylib that can be linked to. It seems to work based on the limited testing I performed. It looks like support for shared objects/dynamic libraries is very limited, so there is a good chance that there will be another hurdle to overcome.

Anya Shenanigans
  • 91,618
  • 3
  • 107
  • 122
  • Seems that your solution is most acceptable to me, as I'm writing in D, not in C, and your solution does not involve GCC-specific stuff. The only things to be called in these constructor and destructor are D runtime initialization and termination. – toriningen Mar 18 '12 at 17:18
  • Can you also hint, what is ld flag for specifying destructors? – toriningen Mar 18 '12 at 17:20
  • 1
    The equivalent for the finalizer/destructor is to use the -fini option. – Anya Shenanigans Mar 18 '12 at 21:03
  • Unfortunately, no -fini in OSX' ld. – toriningen Mar 19 '12 at 05:11
  • No dylib unloading either - you can only unload bundles, and bundles don't support the -init syntax. I would recommend trying to determine the equivalent of __attribute__((constructor)) and __attribute__((destructor)) for the `D` programming language – Anya Shenanigans Mar 19 '12 at 11:43
  • 2
    For `D` you can use the `static this() {}` class constructor semantic, and the `static ~this() {}` class destructor semantic rather than trying to work around flags being passed to the linker. This would be the most preferable mechanism for the language – Anya Shenanigans Mar 19 '12 at 11:49
  • Thank you, Petesh, I will try to check if this mechanism is applicable for initializing (and terminating) D runtime when C core loads plugin written in D. – toriningen Mar 20 '12 at 18:24
  • I've updated the answer with some more code that should get more along the way to producing libraries(.so/.dylib) that auto-execute attach/detach routines. – Anya Shenanigans Mar 20 '12 at 23:01
  • Regarding "Edit 3 ": You can just mark attach/detach as "extern(C)" (and maybe 'export' as well, I'm not sure) to avoid name mangling. However, once the D shared library support is finished, all that should be set up by the compiler/runtime and static this / shared static this should just work. – jpf Mar 21 '12 at 14:01
  • @jpf Cool, that looks like it worked for removing the mangling. It does make more sense to wait for the full shared library support to arrive rather than jury-rigging a solution like this (which is essentially what it is) – Anya Shenanigans Mar 21 '12 at 14:09
16

To have a function executed whenever the shared library is loaded or unloaded, you can mark a constructor and destructor function using GCC-specific attribute syntax:

__attribute__((constructor)) void init(void) { ... }
__attribute__((destructor))  void fini(void) { ... }

Because various parts of a C environment depend on things being initialized in the standard .init code added by GCC behind the scenes, directly using -Wl,-init,<function name> may cause your program to crash.

For more information, see the Libary HOWTO on Library constructor and destructor functions.

Daniel Roethlisberger
  • 6,958
  • 2
  • 41
  • 59
  • 2
    Important note: you can't use any prints in the "constructor", apparently because stdout, stderr don't exist yet. E.g. for me doing a `cout` for debugging purposes led to crash. – Hi-Angel Apr 30 '19 at 23:18
6

GCC, and also clang AFAIK, support the GCC constructor and destructor attributes. For more details, see How exactly does __attribute__((constructor)) work?

Community
  • 1
  • 1
janneb
  • 36,249
  • 2
  • 81
  • 97
4

For C++ you can create a class and use his constructor and destructor to initialize the library.

After, you only need to define a variable for this class.

Example initializing openssl in the library:

class InitLibrary {
public:
  InitLibrary() {
    CRYPTO_malloc_init(); // Initialize malloc, free, etc for OpenSSL's use
    SSL_library_init(); // Initialize OpenSSL's SSL libraries
    SSL_load_error_strings(); // Load SSL error strings
    ERR_load_BIO_strings(); // Load BIO error strings
    OpenSSL_add_all_algorithms(); // Load all available encryption algorithms
  }

  ~InitLibrary() {
    ERR_remove_state(0);
    CRYPTO_cleanup_all_ex_data();
    ENGINE_cleanup();
  }
};

and only add this line in cpp file: InitLibrary InitLib;

oml
  • 115
  • 2
  • 8