1

I have tested such a simple program below

/* a shared library */
dispatch_write_hello(void)
{
        fprintf(stderr, "hello\n");
}

extern void
print_hello(void)
{
        dispatch_write_hello();
}

My main program is like this:

extern void
dispatch_write_hello(void)
{
        fprintf(stderr, "overridden\n");
}

int
main(int argc, char **argv)
{
        print_hello();
        return 0;
}

The result of the program is "overriden".
To figure this out why this happens, I used gdb. The call chain is like this:
_dl_runtime_resolve -> _dl_fixup ->_dl_lookup_symbol_x
I found the definition of _dl_lookup_symbol_x in glibc is

Search loaded objects' symbol tables for a definition of the symbol UNDEF_NAME, perhaps with a requested version for the symbol

So I think when trying to find the symbol dispatch_write_hello, it first of all looks up in the main object file, and then in the shared library. This is the cause of this problem. Is my understanding right? Many thanks for your time.

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
HuangJie
  • 1,488
  • 1
  • 16
  • 33

1 Answers1

2

Given that you mention _dl_runtime_resolve, I assume that you're on Linux system (thanks @Olaf for clarifying this).

A short answer to your question - yes, during symbols interposition dynamic linker will first look inside the executable and only then scan shared libraries. So definition of dispatch_write_hello will prevail.

EDIT

In case you wonder why runtime linker needs to resolve the call to dispatch_write_hello in print_hello to anything besides dispatch_write_hello in the same translation unit - this is caused by so called semantic interposition support in GCC. By default compiler treats any call inside library code (i.e. code compiled with -fPIC) as potentially interposable at runtime unless you specifically tell it not to, via -fvisibility-hidden, -Wl,-Bsymbolic, -fno-semantic-interposition or __attribute__((visibility("hidden"))). This has been discussed on the net many times e.g. in the infamous Sorry state of dynamic libraries on Linux.

As a side note, this feature incures significant performance penalty compared to other compilers (Clang, Visual Studio).

yugr
  • 19,769
  • 3
  • 51
  • 96
  • Which "dynamic linker"? That depends on the platform. Without that we only have the C standard. – too honest for this site Mar 12 '17 at 17:37
  • @Olaf OP mentioned `_dl_runtime_resolve` which means that he's on Linux or Android (or Solaris?) which all behave the same wrt shared libs and interposition. – yugr Mar 12 '17 at 18:01
  • Nice explanation, but I am not convinced. In the shared lib, the dispatch_write_hello() has nothing strange. Why print_hello() in the same file, which calls dispatchxxx(), needs to resolve a symbol? There is something obscure for me. – linuxfan says Reinstate Monica Mar 12 '17 at 19:30
  • @linuxfan Because that's how shared libs work on Linux by default. You can alter this behavior with `-fvisibility-hidden`, `-Bsymbolic` or `-fno-semantic-interposition` - but only if you really understand what your are doing. For primer on Linux shlibs see any of numerous tutorials on the net e.g. the infamous [Sorry state of dynamic libraries on Linux](http://www.macieira.org/blog/2012/01/sorry-state-of-dynamic-libraries-on-linux/). – yugr Mar 12 '17 at 21:45
  • @yugr @linuxfan By setting `LD_DEBUG=symbols,bindings`, we can verify that `dispatch_write_hello` is looked up in the executable file first. – HuangJie Mar 13 '17 at 01:11
  • Thank you for addressing my doubt. There was some kind of evidence, but your edit in the answer clarifies well. – linuxfan says Reinstate Monica Mar 13 '17 at 06:46