Android中缺失dlinfo与dladdr1,如何获取link_map及动态段信息?
Android 获取link_map结构体与共享对象动态段的替代方案
方案1:解析/proc/self/maps与ELF文件
直接读取/proc/self/maps文件,获取所有加载的共享库、主可执行文件的加载基地址和文件路径:
- 主可执行文件对应路径为
/proc/self/exe,共享库路径则指向系统或应用lib目录下的so文件 - 拿到基地址和路径后,打开目标ELF文件,解析ELF头找到
PT_DYNAMIC类型的程序段,结合加载基地址计算出动态段的虚拟地址,即可读取动态段的所有条目(如DT_HASH、DT_STRTAB等)
注意:需确保进程有读取/proc目录和对应ELF文件的权限,Android高版本SELinux可能限制对系统库的直接读取,但自身进程的文件通常不受影响。
方案2:利用libdl的私有符号(兼容性需验证)
Android的libdl库中存在未公开的link_map链表入口,可通过dlsym尝试获取:
#include <dlfcn.h> typedef struct link_map link_map; link_map* g_link_map = dlsym(RTLD_DEFAULT, "__link_map");
拿到链表头后,可遍历每个link_map节点:
l_addr:当前共享库/主程序的加载基地址l_name:对应文件的路径l_ld:动态段的虚拟地址(直接指向动态段起始位置)
不过要注意:私有符号在不同Android版本中可能存在变更,Android 11及以上对私有API限制更严格,此方法仅适合特定版本调试或兼容场景。
方案3:使用公开接口dl_iterate_phdr(推荐)
NDK提供的dl_iterate_phdr是最稳定的公开方案,可遍历所有加载的ELF镜像(包括主可执行文件):
#include <link.h> int callback(struct dl_phdr_info* info, size_t size, void* data) { // info->dlpi_addr:加载基地址 // info->dlpi_name:文件路径 for (int i = 0; i < info->dlpi_phnum; i++) { const ElfW(Phdr)* phdr = &info->dlpi_phdr[i]; if (phdr->p_type == PT_DYNAMIC) { // 动态段的虚拟地址 = info->dlpi_addr + phdr->p_vaddr ElfW(Dyn)* dyn = (ElfW(Dyn)*)(info->dlpi_addr + phdr->p_vaddr); // 遍历dyn数组,解析动态段条目 while (dyn->d_tag != DT_NULL) { // 处理每个d_tag,如DT_STRTAB、DT_SYMTAB等 dyn++; } break; } } return 0; } dl_iterate_phdr(callback, NULL);
该接口从Android 4.0(API level 14)开始支持,兼容性好,无需依赖私有符号,是优先推荐的方案。
内容的提问来源于stack exchange,提问作者localacct
相关产品推荐
相关产品推荐

