Dear Maintainer,
I was trying to learn the effects of
--no-undefined
--no-allow-shlib-undefined
--as-needed
--no-copy-dt-needed-entries
and did some tests for that.
The results of those tests differed from ld.bfd to ld.gold, and IMO, the
behavior of ld.bfd is better (safer). It catches an error at link time,
instead of deferring it to run time.
I would expect --no-allow-shlib-undefined to search recursively through
all of my dependencies and check if any of them has undefined symbols,
and report an error if so. ld.bfd has that behavior.
Instead, ld.gold only checks that my direct dependencies have their symbols
resolved, but it does not check the dependencies of my dependencies.
That creates the possibility that an unmet dependency will cause a run-time
error, as I show in the example below.
Thanks,
Alex
alx@sqli:~/src/test/lib$ ll
total 20
-rw-r--r-- 1 user user 29 Oct 28 11:47 bar.c
-rw-r--r-- 1 user user 60 Oct 28 13:47 foobar.c
-rw-r--r-- 1 user user 83 Oct 28 11:46 foo.c
-rw-r--r-- 1 user user 52 Oct 28 13:47 foovar.c
-rw-r--r-- 1 user user 56 Oct 28 13:31 main.c
alx@sqli:~/src/test/lib$
alx@sqli:~/src/test/lib$ cat bar.c
int bar(void)
{
return 1;
}
alx@sqli:~/src/test/lib$ cat foo.c
int bar(void);
int foo(void)
{
return 1;
}
int foo_bar(void)
{
return bar();
}
alx@sqli:~/src/test/lib$ cat foobar.c
int foo_bar(void);
int foobar(void)
{
return foo_bar();
}
alx@sqli:~/src/test/lib$ cat foovar.c
int foo(void);
int foobar(void)
{
return foo();
}
alx@sqli:~/src/test/lib$ cat main.c
int foobar(void);
int main(void)
{
return foobar();
}
alx@sqli:~/src/test/lib$
alx@sqli:~/src/test/lib$ cc -c -fpic -Wall -Wextra -Werror main.c foo.c bar.c foobar.c foovar.c
alx@sqli:~/src/test/lib$
alx@sqli:~/src/test/lib$ cc -shared -Wl,--no-undefined -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libbar.so bar.o -fuse-ld=bfd
alx@sqli:~/src/test/lib$ cc -shared -Wl,--no-undefined -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libbar.so bar.o -fuse-ld=gold
alx@sqli:~/src/test/lib$
alx@sqli:~/src/test/lib$ cc -shared -Wl,--no-undefined -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libfoo.so foo.o -fuse-ld=bfd
/usr/bin/ld.bfd: foo.o: in function `foo_bar':
foo.c:(.text+0x10): undefined reference to `bar'
collect2: error: ld returned 1 exit status
alx@sqli:~/src/test/lib$ cc -shared -Wl,--no-undefined -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libfoo.so foo.o -fuse-ld=gold
foo.o:foo.c:function foo_bar: error: undefined reference to 'bar'
collect2: error: ld returned 1 exit status
alx@sqli:~/src/test/lib$
alx@sqli:~/src/test/lib$ cc -shared -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libfoo.so foo.o -fuse-ld=bfd
alx@sqli:~/src/test/lib$ cc -shared -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libfoo.so foo.o -fuse-ld=gold
alx@sqli:~/src/test/lib$
alx@sqli:~/src/test/lib$ cc -shared -Wl,--no-undefined -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libfoobar.so foobar.o -L. -lfoo -fuse-ld=bfd
/usr/bin/ld.bfd: ./libfoo.so: undefined reference to `bar'
collect2: error: ld returned 1 exit status
alx@sqli:~/src/test/lib$ cc -shared -Wl,--no-undefined -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libfoobar.so foobar.o -L. -lfoo -fuse-ld=gold
./libfoo.so: error: undefined reference to 'bar'
collect2: error: ld returned 1 exit status
alx@sqli:~/src/test/lib$
alx@sqli:~/src/test/lib$ cc -shared -Wl,--no-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libfoobar.so foobar.o -L. -lfoo -fuse-ld=bfd
alx@sqli:~/src/test/lib$ cc -shared -Wl,--no-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libfoobar.so foobar.o -L. -lfoo -fuse-ld=gold
alx@sqli:~/src/test/lib$
alx@sqli:~/src/test/lib$ cc -shared -Wl,--no-undefined -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libfoovar.so foovar.o -L. -lfoo -fuse-ld=bfd
/usr/bin/ld.bfd: ./libfoo.so: undefined reference to `bar'
collect2: error: ld returned 1 exit status
alx@sqli:~/src/test/lib$ cc -shared -Wl,--no-undefined -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libfoovar.so foovar.o -L. -lfoo -fuse-ld=gold
./libfoo.so: error: undefined reference to 'bar'
collect2: error: ld returned 1 exit status
alx@sqli:~/src/test/lib$
alx@sqli:~/src/test/lib$ cc -shared -Wl,--no-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libfoovar.so foovar.o -L. -lfoo -fuse-ld=bfd
alx@sqli:~/src/test/lib$ cc -shared -Wl,--no-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o libfoovar.so foovar.o -L. -lfoo -fuse-ld=gold
alx@sqli:~/src/test/lib$
alx@sqli:~/src/test/lib$ # NOTE: bfd and gold behave differently here!
alx@sqli:~/src/test/lib$ # gold will produce a buggy binary!!
alx@sqli:~/src/test/lib$ cc -Wl,--no-undefined -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o foobar -Wl,-rpath=. main.o -L. -lfoobar -fuse-ld=bfd
/usr/bin/ld.bfd: ./libfoo.so: undefined reference to `bar'
collect2: error: ld returned 1 exit status
alx@sqli:~/src/test/lib$ cc -Wl,--no-undefined -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o foobar -Wl,-rpath=. main.o -L. -lfoobar -fuse-ld=gold
alx@sqli:~/src/test/lib$
alx@sqli:~/src/test/lib$ LD_LIBRARY_PATH=. ./foobar
./foobar: symbol lookup error: ./libfoo.so: undefined symbol: bar
alx@sqli:~/src/test/lib$
alx@sqli:~/src/test/lib$ # NOTE: bfd and gold behave differently here!
alx@sqli:~/src/test/lib$ # gold will produce a binary that luckily works here,
alx@sqli:~/src/test/lib$ # but might break inadvertently if
alx@sqli:~/src/test/lib$ # a future libfoovar starts using foo_bar()!
alx@sqli:~/src/test/lib$ cc -Wl,--no-undefined -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o foovar -Wl,-rpath=. main.o -L. -lfoovar -fuse-ld=bfd
/usr/bin/ld.bfd: ./libfoo.so: undefined reference to `bar'
collect2: error: ld returned 1 exit status
alx@sqli:~/src/test/lib$ cc -Wl,--no-undefined -Wl,--no-allow-shlib-undefined -Wl,--as-needed -Wl,--no-copy-dt-needed-entries -o foovar -Wl,-rpath=. main.o -L. -lfoovar -fuse-ld=gold
alx@sqli:~/src/test/lib$
alx@sqli:~/src/test/lib$ LD_LIBRARY_PATH=. ./foovar
alx@sqli:~/src/test/lib$