在不同的动态加载对象中以不同方式解析符号

Resolving symbols differently in different dynamically loaded objects

阅读 these questions 后,我正在寻找有关如何控制符号解析顺序的更多详细信息。

在我的问题中,我有主要的可执行文件 execexec 动态 link 到 a.soc.soa.so 动态 link 到 b.sob.so 调用函数 foo,通常由 c.so 提供,但在本例中也由 exec 提供。 b.so 仅适用于 c.sofoo 的实现。

情况图:

exec      (foo caller and provider)
   | \
a.so  |
   |  |
b.so  |   (foo caller)
   | /
c.so      (foo provider)

我只能控制a.so的compilation/source,我linka.soexecLD_PRELOAD.

我想在 exec 中调用 foo 以解析为 exec 的实现,并在 b.so 中调用以解析为 c.so的实施。这种在不同对象中使用不同符号查找的东西可能吗?

不幸的是,没有办法在每个库级别调整符号解析,因此没有简单的方法来实现这一点。

如果 foo 实际上是在主要可执行文件中实现的(而不仅仅是 copy-relocated ),您无能为力,因为主要可执行文件中的符号在解析过程中获得最高优先级(除非你对 GOT 的最终 hacky runtime-patching 没问题,但你不是。

但是如果

  • foo在c.so
  • 中实现
  • 你已经够绝望了

您可以执行以下操作:

  • 在 a.so 中获取 return 拦截器内的地址(使用 __builtin_return_address
  • 将其与 b.so 的边界相匹配(可以从 /proc/self/maps 获得)
  • 根据结果,进行特殊处理(如果调用者在 b.so)或将调用转发给 RTLD_NEXT

这当然有明显的局限性,例如如果 b.so 从另一个 d.so 调用函数,然后调用 foo,则将不起作用,但在许多情况下可能就足够了。是的,我已经在实践中看到了这种方法。