Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Isn't ld checking for unresolved symbols in shared libraries redundant?

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?

like image 368
elik Avatar asked Dec 19 '22 10:12

elik


1 Answers

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.

like image 116
Mike Kinghan Avatar answered Mar 15 '23 23:03

Mike Kinghan