如何从句柄(macOS/iOS)获取库的路径



我有一个动态库的句柄(来自使用dlopen())。不管为什么,我无法访问提供给dlopen()的路径,但需要另一个函数的路径。因此,我需要能够使用它的句柄获取到库的路径。

我试过使用dladdr(),就像我在应用程序的其他部分一样,但在macOS/iOS上,你无法使用它来查找库的路径,因为它只能与库中符号的句柄一起使用。我可以尝试在库中添加一个"定位器符号",并以这种方式完成任务,但我不愿意这样做

我还尝试了dlinfo()RTLD_DI_LINKMAP,但这显然在macOS/iOS上不可用。

我很惊讶关于这方面的信息如此之少。许多解决方案在macOS/iOS上都不可用。其他人仍然只是获取当前可执行文件的路径,与句柄无关。

经过一顿搜索,我终于找到了一些资源,说要使用_dyld_image_count()_dyld_get_image_name()迭代所有加载的图像。我最初决定不这样做,因为这似乎不是一种不合理的缓慢做事方式。

最终,我决定对所有加载的图像进行迭代,因为这是我遇到的唯一实际解决方案。我在谷歌上搜索了一些例子,但找不到任何关于这个主题的教程。然而,我确实遇到了一个实现该功能的开源C++库(在这里找到)。

我把它翻译成了普通的C,并去掉了一些多余的东西(比如去掉手柄)。在测试过程中,我注意到我想要的库总是在列表中的最后一个(我的最佳猜测是,它按加载顺序存储它们,由于我的库不是系统库,它将是最后加载的库之一)。这保证了缓慢的性能(对于计算机来说——对于人类来说,它仍然几乎是瞬间的)。因此,我做了一个巧妙的优化,从列表的结尾开始搜索,而不是从开头开始。

这是我的解决方案的最终代码:

// NOT a thread safe way of doing things
NSString *pathFromHandle(void* handle)
{
// Since we know the image we want will always be near the end of the list, start there and go backwards
for (uint32_t i = (_dyld_image_count() - 1); i >= 0; i--)
{
const char* image_name = _dyld_get_image_name(i);
// Why dlopen doesn't effect _dyld stuff: if an image is already loaded, it returns the existing handle.
void* probe_handle = dlopen(image_name, RTLD_LAZY);
dlclose(probe_handle);
if (handle == probe_handle)
{
return [NSString stringWithUTF8String:image_name];
}
}

return NULL;
}

需要注意的是,此解决方案不是线程安全的,因为_dyld_image_count()_dyld_get_image_name()本质上是不线程安全的。这意味着任何其他线程都可能加载/卸载图像,并对我们的搜索产生负面影响。

此外,我使用的资源质疑为什么dlopen_dyld_image_count()没有影响。这是因为如果已经加载了图像,dlopen不会加载该图像的新实例,而是返回该图像的现有句柄

最新更新