【问题标题】:Automatically executed functions when loading shared libraries加载共享库时自动执行的函数
【发布时间】:2012-04-03 07:56:36
【问题描述】:

在 Windows 中加载共享库时,LoadLibrary() 调用会导致库中的 DllMain 为每个新进程和线程库附加到,以及每个进程和线程库从其中分离执行。

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

【问题讨论】:

标签: posix shared-libraries d dlopen


【解决方案1】:

您可以使用.init 机制为 linux 库定义加载函数。这与指定二进制文件的加载时入口点相同(例如,使用 main 以外的东西作为程序的入口点)。

当直接使用ld 链接时,您使用:

-init <function name>

或者如果您使用 cc/gcc 链接,则使用:

-Wl,-init,<function name>

这是最简单的。

编辑 对于析构器/终结器,您使用.fini 机制。这与 init 选项的操作方式相同,您可以使用:

-fini <function name>

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

您还应该能够对 gcc 使用 __attribute__((constructor)) 语法:

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 代码中的所有静态构造函数/析构函数。

初始化程序的 Stub d 代码(在名为 myshared.d 的文件中):

import core.runtime;

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

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

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

为此存根创建 .o:

 dmd -m32 -c myshared.d

检查附加/分离函数的名称:

nm myshared.o

显示(以及其他输出):

0000001c S _D8myshared6attachFZv
00000034 S _D8myshared6detachFZv

用于调用它的示例 .c 代码(在本例中称为 export.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。根据我执行的有限测试,它似乎有效。看起来对共享对象/动态库的支持非常有限,因此很有可能还会有另一个障碍需要克服。

【讨论】:

  • 似乎你的解决方案是我最能接受的,因为我用 D 语言而不是 C 语言编写,而且你的解决方案不涉及 GCC 特定的东西。在这些构造函数和析构函数中唯一需要调用的是 D 运行时初始化和终止。
  • 你能否提示一下,指定析构函数的 ld 标志是什么?
  • 终结器/析构函数的等价物是使用 -fini 选项。
  • 不幸的是,OSX 的 ld 中没有 -fini。
  • 对于D,您可以使用static this() {} 类构造函数语义和static ~this() {} 类析构函数语义,而不是尝试解决传递给链接器的标志。这将是该语言最可取的机制
【解决方案2】:

要在加载或卸载共享库时执行函数,您可以使用 GCC 特定的属性语法标记构造函数和析构函数:

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

因为 C 环境的各个部分都依赖于 GCC 在幕后添加的标准 .init 代码中初始化的东西,所以直接使用 -Wl,-init,&lt;function name&gt; 可能会导致您的程序崩溃。

有关详细信息,请参阅 Library constructor and destructor functions 上的库 HOWTO。

【讨论】:

  • 重要提示:您不能在“构造函数”中使用任何打印,显然是因为 stdout、stderr 还不存在。例如。对我来说,出于调试目的使用cout 导致崩溃。
【解决方案3】:

GCC 和 clang AFAIK 支持 GCC 构造函数和析构函数属性。更多详情请见How exactly does __attribute__((constructor)) work?

【讨论】:

    【解决方案4】:

    对于 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;

    【讨论】:

      猜你喜欢
      • 2012-07-08
      • 2019-08-18
      • 2011-08-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-10
      • 2011-05-29
      相关资源
      最近更新 更多