Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/joomla/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 从OSX上的dlopen句柄查找路径名_C_Macos_Dyld - Fatal编程技术网

C 从OSX上的dlopen句柄查找路径名

C 从OSX上的dlopen句柄查找路径名,c,macos,dyld,C,Macos,Dyld,我已经dlopen()”创建了一个库,我想将它传递给我的句柄反转回共享库的完整路径名。在Linux和friends上,我知道我可以使用dlinfo()获取链接图并遍历这些结构,但在OSX上似乎找不到类似的方法。我能做的最接近的事情是: 使用dyld\u image\u count()和dyld\u get\u image\u name(),迭代所有当前打开的库,希望我能猜出哪个库对应于我的句柄 以某种方式找到一个位于我的句柄内部的符号,并将其传递给dladdr() 如果我对刚刚打开的库中的符

我已经
dlopen()
”创建了一个库,我想将它传递给我的句柄反转回共享库的完整路径名。在Linux和friends上,我知道我可以使用
dlinfo()
获取链接图并遍历这些结构,但在OSX上似乎找不到类似的方法。我能做的最接近的事情是:

  • 使用
    dyld\u image\u count()
    dyld\u get\u image\u name()
    ,迭代所有当前打开的库,希望我能猜出哪个库对应于我的句柄

  • 以某种方式找到一个位于我的句柄内部的符号,并将其传递给
    dladdr()

如果我对刚刚打开的库中的符号名有先验知识,我可以
dlsym()
然后使用
dladdr()
。那很好。但在一般情况下,我不知道这个共享库中有什么,我需要能够枚举符号来完成这项工作,我也不知道如何完成


因此,关于如何从库的
dlopen
句柄中查找库的路径名的任何提示都将非常感谢。谢谢

以下是如何获取由
dlopen
返回的句柄的绝对路径

  • 为了获得绝对路径,您需要调用
    dladdr
    函数并检索
    Dl\u info.dli\u fname
    字段
  • 要调用
    dladdr
    函数,需要给它一个地址
  • 为了获得给定句柄的地址,必须使用符号调用
    dlsym
    函数
  • 为了从加载的库中获取符号,您必须解析库以找到其符号表并迭代符号。您需要查找外部符号,因为
    dlsym
    仅搜索外部符号
  • 把它们放在一起,你会得到:

    #import <dlfcn.h>
    #import <mach-o/dyld.h>
    #import <mach-o/nlist.h>
    #import <stdio.h>
    #import <string.h>
    
    #ifdef __LP64__
    typedef struct mach_header_64 mach_header_t;
    typedef struct segment_command_64 segment_command_t;
    typedef struct nlist_64 nlist_t;
    #else
    typedef struct mach_header mach_header_t;
    typedef struct segment_command segment_command_t;
    typedef struct nlist nlist_t;
    #endif
    
    static const char * first_external_symbol_for_image(const mach_header_t *header)
    {
        Dl_info info;
        if (dladdr(header, &info) == 0)
            return NULL;
    
        segment_command_t *seg_linkedit = NULL;
        segment_command_t *seg_text = NULL;
        struct symtab_command *symtab = NULL;
    
        struct load_command *cmd = (struct load_command *)((intptr_t)header + sizeof(mach_header_t));
        for (uint32_t i = 0; i < header->ncmds; i++, cmd = (struct load_command *)((intptr_t)cmd + cmd->cmdsize))
        {
            switch(cmd->cmd)
            {
                case LC_SEGMENT:
                case LC_SEGMENT_64:
                    if (!strcmp(((segment_command_t *)cmd)->segname, SEG_TEXT))
                        seg_text = (segment_command_t *)cmd;
                    else if (!strcmp(((segment_command_t *)cmd)->segname, SEG_LINKEDIT))
                        seg_linkedit = (segment_command_t *)cmd;
                    break;
    
                case LC_SYMTAB:
                    symtab = (struct symtab_command *)cmd;
                    break;
            }
        }
    
        if ((seg_text == NULL) || (seg_linkedit == NULL) || (symtab == NULL))
            return NULL;
    
        intptr_t file_slide = ((intptr_t)seg_linkedit->vmaddr - (intptr_t)seg_text->vmaddr) - seg_linkedit->fileoff;
        intptr_t strings = (intptr_t)header + (symtab->stroff + file_slide);
        nlist_t *sym = (nlist_t *)((intptr_t)header + (symtab->symoff + file_slide));
    
        for (uint32_t i = 0; i < symtab->nsyms; i++, sym++)
        {
            if ((sym->n_type & N_EXT) != N_EXT || !sym->n_value)
                continue;
    
            return (const char *)strings + sym->n_un.n_strx;
        }
    
        return NULL;
    }
    
    const char * pathname_for_handle(void *handle)
    {
        for (int32_t i = _dyld_image_count(); i >= 0 ; i--)
        {
            const char *first_symbol = first_external_symbol_for_image((const mach_header_t *)_dyld_get_image_header(i));
            if (first_symbol && strlen(first_symbol) > 1)
            {
                handle = (void *)((intptr_t)handle | 1); // in order to trigger findExportedSymbol instead of findExportedSymbolInImageOrDependentImages. See `dlsym` implementation at http://opensource.apple.com/source/dyld/dyld-239.3/src/dyldAPIs.cpp
                first_symbol++; // in order to remove the leading underscore
                void *address = dlsym(handle, first_symbol);
                Dl_info info;
                if (dladdr(address, &info))
                    return info.dli_fname;
            }
        }
        return NULL;
    }
    
    int main(int argc, const char * argv[])
    {
        void *libxml2 = dlopen("libxml2.dylib", RTLD_LAZY);
        printf("libxml2 path: %s\n", pathname_for_handle(libxml2));
        dlclose(libxml2);
        return 0;
    }
    
    #导入
    #进口
    #进口
    #进口
    #进口
    #ifdef_uulp64__
    typedef结构马赫数收割台64马赫数收割台;
    类型定义结构段命令64段命令;
    typedef struct nlist_64 nlist_t;
    #否则
    typedef结构机械头机械头机械头;
    类型定义结构段命令段命令;
    typedef struct nlist nlist\t;
    #恩迪夫
    静态常量字符*第一个外部\u符号\u用于\u图像(常量马赫\u标头\u t*标头)
    {
    Dl_信息;
    if(dladdr(标题和信息)==0)
    返回NULL;
    段_命令_t*seg_linkedit=NULL;
    段_命令_t*seg_text=NULL;
    struct symtab_命令*symtab=NULL;
    struct load_command*cmd=(struct load_command*)((intptr_t)头文件+sizeof(mach_头文件));
    对于(uint32_t i=0;incmds;i++,cmd=(struct load_command*)((intptr_t)cmd+cmd->cmdsize))
    {
    开关(指令->指令)
    {
    案例LC_段:
    案例LC_段_64:
    如果(!strcmp(((segment_command_t*)cmd)->segname,SEG_TEXT))
    seg_text=(段命令_t*)cmd;
    如果(!strcmp(((segment_command_t*)cmd)->segname,SEG_LINKEDIT))
    seg_linkedit=(段命令)cmd;
    打破
    案例LC\U SYMTAB:
    symtab=(struct symtab_command*)cmd;
    打破
    }
    }
    if((seg_text==NULL)| |(seg_linkedit==NULL)| |(symtab==NULL))
    返回NULL;
    intptr_t file_slide=((intptr_t)seg_linkedit->vmaddr-(intptr_t)seg_text->vmaddr)-seg_linkedit->fileoff;
    intptr_t strings=(intptr_t)头+(symtab->stroff+文件幻灯片);
    nlist_t*sym=(nlist_t*)((intptr_t)头+(symtab->symoff+文件幻灯片));
    对于(uint32_t i=0;insyms;i++,sym++)
    {
    如果((sym->n_类型和n_外部)!=n_外部| |!sym->n_值)
    继续;
    返回(const char*)字符串+sym->n\u un.n\u strx;
    }
    返回NULL;
    }
    常量字符*路径名\u用于\u句柄(无效*句柄)
    {
    对于(int32_t i=_dyld_image_count();i>=0;i--)
    {
    常量字符*第一个\u符号=第一个\u外部\u符号\u图像((常量马赫\u头\u t*)动态\u获取\u图像\u头(i));
    如果(第一个符号和&strlen(第一个符号)>1)
    {
    handle=(void*)((intptr_t)handle | 1);//为了触发findExportedSymbol而不是findExportedSymbolInImageOrDependentImages。请参见http://opensource.apple.com/source/dyld/dyld-239.3/src/dyldAPIs.cpp
    首先_symbol++;//删除前导下划线
    void*address=dlsym(句柄,第一个符号);
    Dl_信息;
    if(数据地址(地址和信息))
    return info.dli_fname;
    }
    }
    返回NULL;
    }
    int main(int argc,const char*argv[]
    {
    void*libxml2=dlopen(“libxml2.dylib”,RTLD_-LAZY);
    printf(“libxml2路径:%s\n”,句柄的路径名(libxml2));
    dlclose(libxml2);
    返回0;
    }
    

    如果您运行此代码,它将产生预期的结果:
    libxml2路径:/usr/lib/libxml2.2.dylib

    使用0xced提供的解决方案大约一年后,我们发现了一种更简单、避免一种(相当罕见)故障模式的替代方法;具体地说,因为0xced的代码段迭代当前加载的每个动态库,查找第一个导出的符号,尝试在当前正在查找的动态库中解析它,如果在该特定动态库中找到该符号,则返回正值,如果从任意库导出的第一个符号恰好出现在当前搜索的动态库中,则可能出现误报

    我的解决方案是使用
    \u dyld\u get\u image\u name(i)
    获取加载的每个图像的绝对路径,
    dlopen()
    该图像,并比较句柄(在屏蔽了
    dlopen()
    设置的任何模式位后,由于使用了
    RTLD\u FIRST
    )以确保此动态库实际上与传递到我的函数中的句柄是同一个文件

    完全函数
    // Iterate through all images currently in memory
    for (int32_t i = _dyld_image_count(); i >= 0 ; i--) {
        // dlopen() each image, check handle
        const char *image_name = _dyld_get_image_name(i);
        uv_lib_t *probe_lib = jl_load_dynamic_library(image_name, JL_RTLD_DEFAULT);
        void *probe_handle = probe_lib->handle;
        uv_dlclose(probe_lib);
    
        // If the handle is the same as what was passed in (modulo mode bits), return this image name
        if (((intptr_t)handle & (-4)) == ((intptr_t)probe_handle & (-4)))
            return image_name;
    }