2

Given these:

bar.cpp:

int foo();

int bar()
{
    return foo();
}

foo.cpp:

int foo()
{
    return 42;
}

The libfoo.so is built by gcc for foo.cpp,i.e. gcc -shared -o libfoo.so -fPIC foo.c

As it's all known that readelf -d could be used to show the dependency of a specific shared library.

$ gcc -shared -o libbar2.so -fPIC bar.c -lfoo -L. 
$ gcc -shared -o libbar.so -lfoo -L. -fPIC bar.c
$ readelf -d libbar2.so | grep -i needed
 0x0000000000000001 (NEEDED)             Shared library: [libfoo.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

$ readelf -d libbar.so | grep -i needed
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

Why the sequence of the parameters passes to the gcc influence the output of readelf -d for the built shared library?

All these tests are on Ubuntu16.04 with gcc 5.4.0.

Update:

$ ls -l libbar*
-rwxrwxr-x 1 joy joy 8000 Oct  4 23:16 libbar2.so
-rwxrwxr-x 1 joy joy 8000 Oct  4 23:16 libbar.so
$ sum -r libbar*
00265     8 libbar2.so
56181     8 libbar.so
John
  • 2,963
  • 11
  • 33
  • fwiw on gcc 8 (windows) both DLLs have the same size (obviously I can't use readelf with that only nm). Isn't gcc 5 old? can you try with a newer gcc? – Jean-François Fabre Oct 05 '21 at 07:32
  • @Jean-François Fabre On `Ubuntu` the size is same too. For details, see the **Update**. `gcc 5` is the default compiler for `Ubuntu 16.04`. I will try to update it. But it is not an easy work as it seems. – John Oct 05 '21 at 07:39

1 Answers1

1

The linking process is sequential and the order in which you specify the files is important. The file are treated in the order they are given. See this extract from the ld manual:

Some of the command-line options to ld may be specified at any point in the command line. However, options which refer to files, such as -l or -T, cause the file to be read at the point at which the option appears in the command line, relative to the object files and other file options.

When you try to link a shared library into another one, the linker will lookup if there is any undefined reference that requires something from the library in all the files considered UP TO NOW(hence in your second example, there is no files prior to the libfoo library ) , and if there is none, the library is left aside, and the linking continue with the remaining files.

Here you also have a behaviour that may be surprising: it is possible (by default) to create shared libraries that still have undefined references (that means they are not self contained). That is what happen in your second example(libbar.so). If you want to avoid this behaviour to be sure you are not in this case you can add the -Wl,-no-undefined option (see https://stackoverflow.com/a/2356393/4871988).

If you add this option the second case will raise an error at link time.

EDIT: I found this other extract in the ld manual that explain this behaviour:

The linker will search an archive only once, at the location where it is specified on the command line. If the archive defines a symbol which was undefined in some object which appeared before the archive on the command line, the linker will include the appropriate file(s) from the archive. However, an undefined symbol in an object appearing later on the command line will not cause the linker to search the archive again. See the -( option for a way to force the linker to search archives multiple times.

You may list the same archive multiple times on the command line.

This also applies to shared libraries

Tomtix
  • 111
  • 5