我有一个动态链接的库,它定义了我需要访问的__attribute__((visibility("hidden")))
符号。这是一个简化的代码
shared.c
__attribute__((visibility("hidden"))) int hidden_sym[12];
int visible_sym[12];
shared_user.c
#include <dlfcn.h>
#include <stdio.h>
int main() {
void* dlopen_res = dlopen("./libnogcc.so", RTLD_LAZY);
if (dlopen_res == NULL) {
printf("dlopen_res is NULL: %sn", dlerror());
return 1;
}
if (dlsym(dlopen_res, "visible_sym") == NULL) {
printf("bb_so is NULL: %sn", dlerror());
return 1;
} else {
printf("'visible_sym' open okn");
}
if (dlsym(dlopen_res, "hidden_sym") == NULL) {
printf("bb_so is NULL: %sn", dlerror());
return 1;
}
}
compilation and execution
gcc shared.c -fpic -shared -olibnogcc.so
gcc -ldl shared_user.c -o shared_main
./shared_main
它正确地加载了visible_symbol
,但预计无法解决隐藏的符号:
'visible_sym' open ok
bb_so is NULL: ./libnogcc.so: undefined symbol: hidden_sym
我想知道是否有任何变通方法可以让我访问隐藏的符号。
请注意,它不需要是基于dlsym
的解决方案。任何允许我访问隐藏符号的东西,而不修改库符号表,都将被视为可接受的解决方案。
我在现实世界中的用例非常相似——我想访问gprof
在插入指令的代码中生成的评测信息。我仍然不能完全确定,但它似乎存储在声明为struct __bb *__bb_head __attribute__((visibility("hidden")));
的__bb_head
变量中。使用<sys/gmon.h>
和<sys/gmon_out.h>
头可以访问结构定义,但我找不到任何方法来实际获取原始形式的分析数据。我知道gprof
允许我在程序执行完成时转储信息,但我需要在运行时获取这些数据,而不必强制写入文件,然后重新读取。
code for accessing libc data
#include <dlfcn.h>
#include <stdio.h>
#include <sys/gmon.h>
#include <sys/gmon_out.h>
int main() {
void* dlopen_res = dlopen("libc.so.6", RTLD_LAZY);
if (dlopen_res == NULL) {
printf("dlopen_res is NULL: %sn", dlerror());
return 1;
}
void* bb_so = dlsym(dlopen_res, "__bb_head");
if (bb_so == NULL) {
printf("bb_so is NULL: %sn", dlerror());
return 1;
}
}
我刚刚在您的简单.so
上做了一个测试。
hidden_sym
确实显示在.symtab
中。
如果你做readelf -a
,你将能够看到它:
6: 0000000000004040 48 OBJECT GLOBAL DEFAULT 21 visible_sym
39: 0000000000004080 48 OBJECT LOCAL DEFAULT 21 hidden_sym
47: 0000000000004040 48 OBJECT GLOBAL DEFAULT 21 visible_sym
dlsym
可能找不到它,但您可以解析readelf
输出或使用libelf
获取符号。
您可以使用/proc/self/maps
查找库的加载地址,然后应用偏移量。
或者,您可以制作.so
文件的副本。然后,通过编辑副本将绑定从LOCAL
更改为GLOBAL
。可能有现有的工具可以让你做到这一点。
然后,dlsym
将能够找到它。
更新:
我确实希望这不是解决这个问题的唯一方法,但我想"隐藏意味着隐藏";在这种情况下,没有可接受的解决方法霍克斯克拉珀
AFAICT,隐藏意味着符号是全局,以便链接形成.so
文件的各种.o
文件可以访问该符号。然后,当.so
被链接时,符号绑定被改变,使其看起来就像上面有static
一样
我接受这个答案,因为它在技术上回答了我的问题,经过一整天的努力,我认为这是我能得到的最好的解决方案,尽管解决方案本身基本上意味着";没有一个合理的解决方案"霍克斯克拉珀
即使符号是全局符号,您也可能无法安全访问/使用它。这是因为您要做的是在数据累积时转储数据。这可能是UB,因为它[可能]没有锁定/冻结数据。
特别是,周期性地发送信号以获得函数直方图[gprof
在内部这样做]与运行的代码[通常]异步。
您必须对其进行测试,以确认您可以安全地访问数据。
您可能可以启动跟踪,等待一段时间,停止跟踪(使用禁止的方法),转储数据。然后,重复这个过程。这不是你说的你想要的,但基于你所说的限制(即没有重建gprof
库等),这可能已经足够妥协了
我想这取决于你想要什么性能数据,以及你愿意花多少精力来检测目标代码以获得它
对于您当前的用例来说,这可能不值得,但如果您要对其他项目进行性能分析,您可以在未来重用您开发的自定义方法论(即,它成为您个人编程的一部分);一袋把戏";。
当我需要性能数据时,我通常会自己滚动。我保持着一个"0"的环形队列;事件";结构。事件可以是任何内容(例如,enter_func、exit_func、func_is_at_line_X等)。
我在每个事件条目中记录时间戳,这样我就可以看到在给定时间在每个函数中花费的确切时间。我也可以看到延迟(gprof
不会提供),尤其是对于多线程应用程序。
也就是说,线程A在时间T1到达点X。它将数据排入线程B,线程A循环并等待更多数据。线程B在时间T2唤醒,将数据排成队列,对其进行处理,并在时间T3返回睡眠。线程A在时间T4唤醒。
现在,如果T2 - T1
是"0";"过量";,那么我们想知道为什么。线程B是否仍在处理以前的请求。还是因为系统负载过重而延迟?T4 - T2
比T4 - T1
时间短吗?
我使这个事件队列线程安全[而AFAICT、gprof
不是]。
我以类似于dtrace
的方式插入代码。
我保留了由全局主标志[或每个事件类型标志的向量]启用的指令插入调用。然后,我可以在远程系统上打开它们(例如在客户站点运行),以在性能"良好"的情况下收集数据;发行";[无论是什么]只显示在一个系统上,配置仅存在于客户的系统中。也就是说,尽管尽了最大努力,问题是在我可以访问的任何实验室/测试系统上都无法复制。
YMMV。。。