【问题标题】:Access dynamic symbol with hidden visibility attribute using `dlsym`使用“dlsym”访问具有隐藏可见性属性的动态符号
【发布时间】:2021-10-16 01:24:47
【问题描述】:

我有一个动态链接库,它定义了我需要访问的__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: %s\n", dlerror());
        return 1;
    }

    if (dlsym(dlopen_res, "visible_sym") == NULL) {
        printf("bb_so is NULL: %s\n", dlerror());
        return 1;
    } else {
        printf("'visible_sym' open ok\n");
    }


    if (dlsym(dlopen_res, "hidden_sym") == NULL) {
        printf("bb_so is NULL: %s\n", 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 变量中。使用&lt;sys/gmon.h&gt;&lt;sys/gmon_out.h&gt; 标头可以访问结构定义,但我无法找到任何方法来实际获取原始形式的分析数据。我知道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: %s\n", dlerror());
        return 1;
    }

    void* bb_so = dlsym(dlopen_res, "__bb_head");
    if (bb_so == NULL) {
        printf("bb_so is NULL: %s\n", dlerror());
        return 1;
    }
}

【问题讨论】:

  • 动态符号表中不存在隐藏符号,所以恐怕你在这里不走运。
  • 除非你能得到一个偏移量并通过一些技巧来计算地址。
  • 那是可悲的。好吧,如果我尝试以某种方式替换分析调用并自己收集信息,也许我的运气会更好,但这几乎与通过偏移/地址进行黑客攻击一样糟糕。
  • 隐藏符号对共享库来说是全局的吗?也就是说,它是否与共享库中的其他对象有外部链接?
  • 无论如何,如果您了解某个函数正在使用的符号,并且该函数隐藏,则可以使用调试器确定如何访问隐藏的符号。如果您能够重建库,您可以简单地暴露隐藏的符号。如果符号声明为static,则它按设计运行。

标签: c linux gcc shared-libraries dynamic-library


【解决方案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找到它。


更新:

我确实希望这不是解决此问题的唯一方法,但我猜在这种情况下“隐藏意味着隐藏”,并且没有可接受的解决方法。 – haxscramper

AFAICT,隐藏意味着符号是全局的,以便链接形成.so 文件的各种.o 文件可以访问该符号。然后,当.so 被链接时,符号绑定发生变化,就好像它上面有static

我接受这个答案是因为它在技术上回答了我的问题,并且经过一整天的尝试寻找解决方法后,我认为这是我可以获得的最佳解决方案,即使解决方案本身基本上意味着“有没有理智的解决方案”。 – haxscramper

即使符号 是全局的,您也可能无法安全地访问/使用它。那是因为你想要做的是在积累数据的同时转储数据。那可能是 UB,因为它 [可能] 不会锁定/冻结数据。

特别是,定期发送信号以获取函数直方图 [gprof 在内部执行] [通常] 与正在运行的代码异步。

您必须对其进行测试以确认您可以安全地访问数据。

您可以开始跟踪,稍等片刻,停止跟踪 [使用禁止的方法],转储数据。并且,重复该过程。这不是您所说的您想要的,但根据您声明的限制(即不重建 gprof 库等),这可能足以妥协。

我想这取决于您想要什么性能数据以及您愿意花费多少精力来检测目标代码以获取它。

对于您当前的用例可能不值得,但如果您要对其他项目进行性能分析,您可以重用您将来开发的自定义方法(即)它成为您个人编程的一部分“一袋花样”。

当我需要性能数据时,我通常会自己滚动。我维护一个“事件”结构的环形队列。事件可以是任何东西(例如)enter_func、exit_func、func_is_at_line_X 等。

我在每个事件条目中记录时间戳,因此我可以看到在给定时间每个函数花费的确切时间。我也可以看到 延迟 [gprof 不会提供],尤其是对于多线程应用程序。

即线程A在时间T1到达X点。它将数据排入线程 B 和线程 A 循环并等待更多数据。线程 B 在时间 T2 唤醒,将数据出列,处理它,然后在时间 T3 重新进入睡眠状态。线程 A 在时间 T4 唤醒。

现在,如果T2 - T1 是“过度”,那么我们想知道原因。线程 B 是否仍在处理先前的请求。还是因为系统负载过重而延迟? T4 - T2 是不是比T4 - T1 少了[这是我们希望的]?

我使这个事件队列线程安全[AFAICT,gprof 不是]。

我以类似于dtrace 的方式检测代码。

我将检测调用留在原地,由全局主标志[或每个事件类型标志的向量]启用。然后,我可以在远程系统上打开它们(例如在客户站点上运行),以在性能“问题”[无论它可能是什么]仅出现在 one 系统上的情况下收集数据在仅存在于客户系统中的配置中。也就是说,尽管尽了最大努力,该问题无法在我可以访问的任何实验室/测试系统上重现。

YMMV ...

【讨论】:

  • 我确实希望这不是解决此问题的唯一方法,但我猜在这种情况下“隐藏意味着隐藏”,并且没有可接受的解决方法。
  • 我接受这个答案是因为它从技术上回答了我的问题,经过一整天的努力寻找解决方法,我认为这是我能做到的最好的解决方案得到,即使解决方案本身基本上意味着“没有理智的解决方案”。
  • @haxscramper 这可能对您的情况有所帮助,也可能无济于事,但我已经更新了我的答案,以描述您可能使用的一些替代方法[我过去曾为自己使用过]。
  • 感谢您的更新。我最终使用了您描述的解决方案并进行了一些修改。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-19
  • 2013-03-12
  • 2020-06-10
  • 2012-05-10
相关资源
最近更新 更多