gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 16:43:03 26 4
gpt4 key购买 nike

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

  • 使用 dyld_image_count()dyld_get_image_name(),遍历所有当前打开的库,希望我能猜出哪个对应于我的句柄

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

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

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

最佳答案

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

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

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

关于c - 从 OSX 上的 dlopen 句柄查找路径名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20481058/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com