加载共享库

问题描述:

当在Windows加载共享库时自动执行功能,LoadLibrary()调用导致DllMain库执行为每个新进程和线程库重视,并为每个进程和线程库deattaches。加载共享库

是否有类似的机制,适用于Mac OS X,Linux和其他可能的POSIX兼容的操作系统?

+0

https://*.com/q/2053029/4361073 – parasrish 2018-01-08 10:07:35

您可以定义一个带载功能使用.init机制的Linux库。这与指定二进制文件的加载时间入口点相同(例如,使用除main以外的内容作为程序的入口点)。

当使用ld链接直接使用:

-init <function name> 

,或者如果你正在使用CC/gcc的链接,您可以使用:

-Wl,-init,<function name> 

这是在它的最简单的层面。

编辑 对于析构函数/终结器,可以使用.fini机制。这个工作在相同的方式初始化选项,并使用:

-fini <function name> 

调用ld时。可用性仅限于Mac OSX平台上的-init选项。

你也应该能够使用__attribute__((constructor))语法GCC:

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

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

这可能是一个更便携的方式,而不是与连接选项拧紧。所有构造函数应在加载时被调用,但取决于他们的初始化顺序,导致精神错乱和不可再现的错误,成本时间和精力去调试上。

编辑2语义的使用__attribute__((constructor))/__attribute__((destructor))是C/C++编程语言的最佳机制。

对于你真的应该使用静态模块构造函数/析构函数D编程语言:

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

还是静态类的构造函数:

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

这是在writing win32 DLLS和强烈暗示语言规范relating to static constructors/destructors

编辑3您将需要在.o链接导出构造函数/析构函数例程,这将允许使用静态初始值设定项。因为它应该做的就是调用Runtime.initialize(),这实际上调用D代码中的所有静态构造函数/析构函数。用于初始化

存根d代码(在一个名为myshared.d):

dmd -m32 -c myshared.d 

检查的附加/分离功能的名称:

import core.runtime; 

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

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

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

这个存根创建的.o: (其他输出):

用于调用这个(在这种情况下,所谓的export.c)
0000001c S _D8myshared6attachFZv 
00000034 S _D8myshared6detachFZv 

样本.C代码,我们引用了出口程序的名称从my shared.o文件:

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(); 
} 

注意,extern void引用需要使用导出函数的重名名称。这些必须匹配或代码不会链接。

使用编译的C代码:

gcc -m32 -c export.c 

链接.c.o一起使用.d.o文件:

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

假设phobos2库是在标准连接器的搜索路径。编译器和链接器的-m32选项的差异是因为我在本地构建的D编译器的版本只支持32位。

这产生了一个可以链接到的.dylib。它似乎基于我执行的有限测试工作。看起来对共享对象/动态库的支持非常有限,所以很有可能会有另一个障碍需要克服。

+0

看来你的解决方案对我来说是最可以接受的,因为我用D编写而不用C编写,而且你的解决方案不涉及GCC特定的东西。在这些构造函数和析构函数中唯一要调用的是D运行时初始化和终止。 – toriningen 2012-03-18 17:18:39

+0

你还可以提示,指定析构函数的ld标志是什么? – toriningen 2012-03-18 17:20:13

+1

终结器/析构函数的等价物是使用-fini 选项。 – Petesh 2012-03-18 21:03:41

要具有每当共享库加载或卸载执行的功能,则可以使用特定GCC-属性语法标记构造和析构函数:

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

因为一个C环境的各个部分依赖于事被GCC在后台添加的标准.init代码初始化后,直接使用-Wl,-init,<function name>可能会导致你的程序崩溃。

欲了解更多信息,请参阅Library constructor and destructor functions的Libary HOWTO。

GCC和clang AFAIK支持GCC构造函数和析构函数属性。有关更多详细信息,请参阅How exactly does __attribute__((constructor)) work?

对于C++,您可以创建一个类并使用其构造函数和析构函数初始化该库。

之后,你只需要为这个类定义一个变量。在图书馆

实例初始化的OpenSSL:

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(); 
    } 
}; 

和只添加这行CPP文件: InitLibrary InitLib;