首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >从OSX上的dlopen句柄查找路径名

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

Stack Overflow用户
提问于 2013-12-09 21:21:44
回答 2查看 3.2K关注 0票数 14

我已经编写了一个dlopen()库,我想将它传递给我的句柄倒转到共享库的完整路径名。在Linux上和我的朋友们,我知道我可以使用dlinfo()获取链接映射并遍历这些结构,但我似乎在OSX上找不到类似的东西。我能做的最接近的事情是:

  • 使用dyld_image_count()dyld_get_image_name(),迭代当前打开的所有库,并希望我能够猜出哪一个对应于我的句柄
  • 以某种方式找到一个存在于我的句柄内的符号,并将它传递给dladdr()

如果我对刚刚打开的库中的符号名有先验的了解,我可以使用dlsym(),然后使用dladdr()。效果很好。但是在一般情况下,我不知道这个共享库中有什么,我需要能够枚举符号才能做到这一点,我也不知道该如何做。

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-05-17 23:58:12

经过大约一年的使用,我们发现了另一种方法,该方法更简单,避免了一种(相当罕见)的失败模式;具体来说,因为0xset的代码片段遍历当前加载的每个dylib,找到第一个导出的符号,尝试在当前正在寻找的dylib中解析它,如果在特定的dylib中找到该符号,则如果从任意库中导出的第一个符号恰好存在于当前正在搜索的dylib中,则可能会出现假阳性。

我的解决方案是使用_dyld_get_image_name(i)获取每个加载的图像的绝对路径,dlopen()该图像,并比较句柄(在屏蔽了dlopen()由于使用RTLD_FIRST之类的东西而设置的任何模式位之后),以确保这个dylib实际上是传递给我函数的句柄的文件。

作为朱莉娅语言一部分的完整函数在这里可以看到,其相关部分复制如下:

代码语言:javascript
运行
复制
// 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;
}

注意,像jl_load_dynamic_library()这样的函数是dlopen()的包装器,返回libuv类型,但是代码的精神保持不变。

票数 10
EN

Stack Overflow用户

发布于 2013-12-19 23:48:10

下面是如何获得dlopen返回的句柄的绝对路径。

  1. 为了获得绝对路径,需要调用dladdr函数并检索Dl_info.dli_fname字段。
  2. 为了调用dladdr函数,您需要给它一个地址。
  3. 为了获得给定句柄的地址,必须使用符号调用dlsym函数。
  4. 为了从加载的库中获取符号,您必须解析库以找到它的符号表并遍历这些符号。您需要找到外部符号,因为dlsym只搜索外部符号。

把这些都放在一起,你就会得到这个:

代码语言:javascript
运行
复制
#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;
}

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

票数 19
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20481058

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档