5

When linking a program against a shared object, ld will ensure that symbols can be resolved. This basically ensures that the interfaces between the program and its shared objects are compatible. After reading Linking with dynamic library with dependencies, I learnt that ld will descend into linked shared objects and attempt to resolve their symbols too.

Aren't my shared object's references already checked when the shared objects are themselves linked?

I can understand the appeal of finding out at link time whether a program has all the pieces it requires to start, but does it seems irrelevant in the context of packages building where shared objects may be distributed separately (Debian's lib* packages, for instance). It introduces recursive build dependencies on systems uninterested in executing built programs.

Can I trust the dependencies resolved when the shared object was built? If so, how safe is it to use -unresolved-symbols=ignore-in-shared-libs when building my program?

Community
  • 1
  • 1
elik
  • 180
  • 1
  • 9

2 Answers2

9

You're wondering why a program's linkage should bother to resolve symbols originating in the shared libraries that it's linked with because:

Aren't my shared object's references already checked when the shared objects are themselves linked?

No they're not, unless you expressly insist on it when you link the shared library,

Here I'm going to build a shared library libfoo.so:

foo.c

extern void bar();

void foo(void)
{
    bar();
}

Routinely compile and link:

$ gcc -fPIC -c foo.c
$ gcc -shared -o libfoo.so foo.o

No problem, and bar is undefined:

$ nm --undefined-only libfoo.so | grep bar
                U bar

I need to insist to get the linker to object to that:

$ gcc --shared -o libfoo.so foo.o -Wl,--no-undefined
foo.o: In function `foo':
foo.c:(.text+0xa): undefined reference to `bar'

Of course:

main.c

extern void foo(void);

int main(void)
{
    foo();
    return 0;
}

it won't let me link libfoo with a program:

$ gcc -c main.c
$ gcc -o prog main.o -L. -lfoo
./libfoo.so: undefined reference to `bar'

unless I also resolve bar in the same linkage:

bar.c

#include <stdio.h>

void bar(void)
{
    puts("Hello world!");
}

maybe by getting it from another shared library:

gcc -fPIC -c bar.c
$ gcc -shared -o libbar.so bar.o
$ gcc -o prog main.o -L. -lfoo -lbar

And then everything's fine.

$ export LD_LIBRARY_PATH=.; ./prog
Hello world!

It's of the essense of a shared library that it doesn't by default have to have all of its symbols resolved at linktime. That way that a program - which typically does need all its symbols resolved a linktime - can get all its symbols resolved by being linked with more than one library.

Mike Kinghan
  • 55,740
  • 12
  • 153
  • 182
  • With the tests I had made, I was left with the impression references were checked when creating a shared object. It got me wondering why it's not the case, but with the case presented by @yugr, checking for references when libraries are build would lead to a chicken-and-egg problem. – elik Jan 28 '17 at 17:17
  • 1
    @Mike: Is there any reason why you don't pass `-Wl,--no-undefined` to the linker? – Andreas Mar 22 '18 at 15:39
  • @Andreas No there isn't! I forgot I was just attempting to *output* an .so forbidding undefined symbols rather than input one. Fixed, good catch. – Mike Kinghan Mar 22 '18 at 20:14
2

Aren't my shared object's references already checked when the shared objects are themselves linked?

Well, shared libs might have been linked with -Wl,--allow-shlib-undefined or with dummy dependencies so it still makes sense to check them.

Can I trust the dependencies resolved when the shared object was built?

Probly not, current linking environment and the environment used to link original shlibs may be different.

If so, how safe is it to use -unresolved-symbols=ignore-in-shared-libs when building my program?

You may be missing potential errors in this case (or rather delaying them to runtime which is still bad). Imagine a situation where some of the symbols needed by shared objects are to come from executable itself or from one of the libs which is linked by executable (but not by the shlib which is missing the symbols).

EDIT

Although above is correct, Mike Kinghan's answer gives stronger argument in favor of symbol resolution in libraries during executable link.

yugr
  • 19,769
  • 3
  • 51
  • 96
  • But if you are building software for distribution, your build environment might differ from the deployed environment too. As far as libraries built with allow-undefined, in the case at hand, I'd be controlling their build as well. +1 for the symbols defined in the executable itself, hadn't thought of that. It sounds like a niche usage (plugin interface, mostly). Is that common? – elik Jan 28 '17 at 16:58
  • @elik "But if you are building software for distribution, your build environment might differ from the deployed environment too" - yes, you'll get the error at runtime in that case. But it's better to detect incompatibilities as early as possible. "It sounds like a niche usage (plugin interface, mostly). Is that common?" - not very common but I added one more use-case which _is_ quite common. – yugr Jan 28 '17 at 17:05
  • @elik All in all, I think Mike's answer is more correct - his argument in favor of symbols resolution during executable link is stronger than mine (although my still hold). – yugr Jan 28 '17 at 17:11
  • Can you give a concrete example for the edit? I understand it, I understand how I could use it, but I fail to see it as being common. – elik Jan 28 '17 at 17:22
  • While I appreciate @Mike's answer ( I didn't know symbols were not checked), you provide stronger arguments as to WHY going that way is a bad idea. – elik Jan 28 '17 at 17:31
  • @elik I don't have example at hand but I remember we faced this a lot when globally enabling `-Wl,--as-needed` in Tizen distro. You can also check Flameeyes posts (e.g. [this one](https://blog.flameeyes.eu/2008/11/relationship-between-as-needed-and-no-undefined-part-1-what-do-they-do/)) which prove that this is not at all uncommon. – yugr Jan 28 '17 at 17:34
  • After careful reviewing my question, I think you are right: @Mike answered my question, which is a simple no, shared libraries's symbols aren't checked when they are built. He also told me how you could make them so. That would have lead to the follow up question: why. I think you give a good answer to that. Do you want me to post it as a separate question? – elik Jan 28 '17 at 18:24
  • @elik Nah, I think it's fine as is. – yugr Jan 28 '17 at 18:28