Resolving symbols differently in different dynamically loaded objects

218 views Asked by At

After reading these questions, I'm looking for some more detail about how to control symbol resolution order.

In my problem, I have main executable exec. exec dynamically links to a.so and c.so. a.so dynamically links to b.so. b.so calls function foo, which is normally provided by c.so but in this case is also provided by exec. b.so only works with c.so's implementation of foo.

A diagram of the situation:

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

I can only control the compilation/source of a.so, and I link a.so to exec with LD_PRELOAD.

I'd like calls to foo in exec to resolve to exec's implementation, and calls in b.so to resolve to c.so's implementation. Is this type of thing with different symbol lookups in different objects possible?

1

There are 1 answers

10
yugr On BEST ANSWER

Unfortunately there is no way to tweak symbol resolution at per-library level so there is not easy way to achieve this.

If foo is actually implemented in main executable (not just copy-relocated to it) there's nothing you can do because symbols from main executables get the highest priority during resolution (unless you are ok with ultimately hacky runtime-patching of GOT which you aren't).

But if

  • foo is implemented in c.so
  • and you are desperate enough

you could do the following:

  • get return address inside interceptor in a.so (use __builtin_return_address)
  • match it against boundaries of b.so (can be obtained from /proc/self/maps)
  • depending on result, either do special processing (if caller is in b.so) or forward call to RTLD_NEXT

This of course has obvious limitations e.g. won't work if b.so calls function from yet another d.so which then calls foo but it may be enough in many cases. And yes, I've seen this approach deployed in practice.