C OSX上动态符号绑定的详细信息是什么?

C OSX上动态符号绑定的详细信息是什么?,c,macos,dyld,C,Macos,Dyld,我在OSX上有一个非常奇怪的动态符号绑定的情况,我希望能得到一些关于如何解决这个问题的线索 我有一个用C编写的应用程序,它使用dlopen()在运行时动态加载模块。其中一些模块导出全局符号,稍后加载的其他模块可能会使用这些符号 我们有一个模块(我称之为怪异模块。因此)可以导出全局符号,其中一个模块是怪异模块功能。如果wird_module.so与一个特定的库(我称之为libsomething.dylib)链接,那么wird_module_函数就不能绑定到它。但是如果我在链接古怪的\u模块时删除-

我在OSX上有一个非常奇怪的动态符号绑定的情况,我希望能得到一些关于如何解决这个问题的线索

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

我们有一个模块(我称之为
怪异模块。因此
)可以导出全局符号,其中一个模块是
怪异模块功能
。如果wird_module.so与一个特定的库(我称之为
libsomething.dylib
)链接,那么
wird_module_函数
就不能绑定到它。但是如果我在链接
古怪的\u模块时删除
-lsomething
,那么我可以绑定到
古怪的\u模块\u函数

libsomething.dylib
可能会发生什么情况,从而导致
模块异常。因此
无法导出符号?我可以做些什么来调试符号如何导出(类似于我如何使用
DYLD\u PRINT\u绑定来调试它们如何绑定)

编辑:

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

首先是
runapp
使用
RTLD_LAZY | RTLD_LOCAL
预加载模块以检查其元数据。然后,根据元数据,使用
RTLD_LAZY | RTLD_GLOBAL
RTLD_NOW | RTLD_LOCAL
打开并重新打开模块。(对于讨论中的两个模块,它都会使用
RTLD_LAZY | RTLD_GLOBAL
重新打开)

第二,在
怪异的_模块中出现了符号冲突。因此,对于
常量
全局变量,
libsomething.dylib

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

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

<>我愿意考虑重复符号会使我处于不明确的行为领域,所以我提出了问题。

< P>我试图重现你的场景,我也能得到和你一样的错误,即:代码> DYLD:懒惰的符号绑定失败 >其次是代码> DyLD:符号未找到 但它与是否针对
libsomething.dylib
进行链接无关。触发此错误的操作只是从
其他\u模块的构造函数调用
怪异的\u模块\u函数()
。因此

//  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();
}
//其他_module.c
#进口
#导入“wird_module.h”
__属性(构造函数)void初始化其他模块(void)
{
printf(“%s\n”,函数);
怪异的_模块_函数();
}
以下是我加载模块的方式:

//  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;
}
//main.c
#进口
#进口
int main(int argc,const char*argv[]
{
printf(“\n加载模块\n”);
void*weird=dlopen(“weird_module.so”,RTLD_LAZY | RTLD_LOCAL);
printf(“怪异:%p\n\n”,怪异);
printf(“加载其他模块”);
void*other=dlopen(“other_module.so”,RTLD_LAZY | RTLD_LOCAL);
printf(“其他:%p\n”,其他);
返回0;
}
如果在加载
wird\u模块时删除
RTLD\u LOCAL
选项,则dyld错误将消失。因此

如果您从
libsomething.dylib
构造函数调用
weird\u module\u函数,也会发生相同的错误,但它发生在调用
main
之前,因此您可能不会遇到这种情况

但是,您应该在
libsomething.dylib
构造函数中查找
libsomething.dylib
是如何影响模块加载过程的。您可以将
DYLD\u PRINT\u初始值设定项
环境变量设置为
YES
,以了解调用的构造函数

需要检查的其他一些事项:

  • 您是否100%确定这两个模块都已使用
    RTLD_LAZY | RTLD_GLOBAL
    重新打开?获取dyld错误的唯一方法是传递
    RTLD\u LOCAL
    选项
  • 是否确定
    dlclose
    调用成功(返回0)?例如,如果您的模块包含Objective-C代码,则不会卸载该模块
  • //  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;
    }