c - OS X 上动态符号绑定(bind)的细节是什么?

标签 c macos dyld

我在 OS X 上的动态符号绑定(bind)遇到了一个非常奇怪的情况,我希望能得到一些关于如何解决的线索。

我有一个用 C 语言编写的应用程序,它使用 dlopen() 在运行时动态加载模块。其中一些模块导出全局符号,这些符号可能会被稍后加载的其他模块使用。

我们有一个模块(我称之为 weird_module.so)导出全局符号,其中之一是 weird_module_function。如果 weird_module.so 与特定库(我称之为 libsomething.dylib)链接,则 weird_module_function 无法绑定(bind)。但是,如果我在链接 weird_module.so 时删除了 -lsomething,那么我可以绑定(bind)到 weird_module_function

libsomething.dylib 可能会发生什么导致 weird_module.so 不导出符号?我可以做些什么来调试符号的导出方式(类似于我如何使用 DYLD_PRINT_BINDINGS 来调试它们的绑定(bind)方式)?

$ LDFLAGS="-bundle -mmacosx-version-min=10.6 -Xlinker -undefined -Xlinker dynamic_lookup /usr/lib/bundle1.o"

$ gcc -o weird_module.so ${LDFLAGS} weird_module.o -lsomething
$ nm weird_module.so | grep '_weird_module_function$'
00000000000026d0 T _weird_module_function

$ gcc -o other_module.so ${LDFLAGS} other_module.o -lsomething
$ nm other_module.so | grep '_weird_module_function$'
                 U _weird_module_function

$ run-app
Loading weird_module.so
Loading other_module.so
dyld: lazy symbol binding failed: Symbol not found: _weird_module_function
  Referenced from: other_module.so
  Expected in: flat namespace

dyld: Symbol not found: _weird_module_function
  Referenced from: other_module.so
  Expected in: flat namespace

# Now relink without -lsomething
$ gcc -o weird_module.so ${LDFLAGS} weird_module.o
$ nm weird_module.so | grep '_weird_module_function$'
00000000000026d0 T _weird_module_function
$ run-app
Loading weird_module.so
Loading other_module.so
# No error!

编辑:

我尝试组装一个最小的应用程序来重现这个问题,并且在这样做的过程中至少弄清楚了一件我们做错的事情。还有两个与重复问题相关的相关事实。

首先是 run-app 使用 RTLD_LAZY | 预加载模块RTLD_LOCAL 检查其元数据。该模块随后被 dlclose() 编辑并使用 RTLD_LAZY | 重新打开。 RTLD_GLOBALRTLD_NOW | RTLD_LOCAL,取决于元数据。 (对于这两个有问题的模块,它使用 RTLD_LAZY | RTLD_GLOBAL 重新打开)。

其次,在 weird_module.solibsomething.dylib 中对于 const 全局存在符号冲突。

$ nm weird_module.so | grep '_something_global`
00000000000158f0 S _something_global

$ nm libsomething.dylib | grep '_something_global'
0000000000031130 S _something_global

我愿意考虑重复符号会使我处于未定义行为的境界,所以我放弃了这个问题。

最佳答案

我试图重现您的场景,但我遇到了与您相同的错误,即 dyld: lazy symbol binding failed 后跟 dyld: Symbol not found

但这与是否链接 libsomething.dylib 无关。我为触发此错误所做的只是从 other_module.so 的构造函数中调用 weird_module_function():

//  other_module.c

#import <stdio.h>
#import "weird_module.h"

__attribute__((constructor)) void initialize_other_module(void)
{
    printf("%s\n", __PRETTY_FUNCTION__);
    weird_module_function();
}

这是我加载模块的方式:

//  main.c

#import <stdio.h>
#import <dlfcn.h>

int main(int argc, const char * argv[])
{
    printf("\nLoading weird module\n");
    void *weird = dlopen("weird_module.so", RTLD_LAZY | RTLD_LOCAL);
    printf("weird: %p\n\n", weird);

    printf("Loading other module\n");
    void *other = dlopen("other_module.so", RTLD_LAZY | RTLD_LOCAL);
    printf("other: %p\n", other);

    return 0;
}

如果我在加载 weird_module.so 时删除 RTLD_LOCAL 选项,dyld 错误就会消失。

如果您从 libsomething.dylib 构造函数调用 weird_module_function 也会发生同样的错误,但它发生在调用 main 之前,所以这可能不是你怎么了。

但也许 libsomething.dylib 构造函数是您应该查看的地方,以了解 libsomething.dylib 是如何影响您的模块加载过程的。您可以将 DYLD_PRINT_INITIALIZERS 环境变量设置为 YES 以找出调用了哪些构造函数。

其他一些要检查的东西:

  1. 您是否 100% 确定这两个模块都已使用 RTLD_LAZY | 重新打开? RTLD_GLOBAL?我得到 dyld 错误的唯一方法是传递 RTLD_LOCAL 选项。
  2. 您确定 dlclose 调用成功(返回 0)吗?例如,如果您的模块包含 Objective-C 代码,它将不会被卸载。

关于c - OS X 上动态符号绑定(bind)的细节是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18701872/

相关文章:

python - 为 Python 和 C 使用通用头文件

objective-c - 不使用 NSView 进行打印

javascript - jshint 验证 es5 错误

objective-c - CMake编译swift项目

macos - ImageMagick:dyld:库未加载。原因:找不到图片

c - 在数组中找到2个元素的总和为目标值

c - linux中每个进程的内存监控

ios - 为什么dyld_decache segfault的解决方案有效?

C:为什么工厂在比较 float 时给出奇怪的结果?

xcode - Xcode 5.0.2 dyld:库未加载:@ rpath/XCTest.framework/Versions/A/XCTest