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;
}