Solve the Linux program compilation link dynamic library version related problems

  • 2020-05-17 07:34:09
  • OfStack

preface

Different versions of the dynamic library may not be compatible, and if the program specifies at compile time that the dynamic library is a lower version and is running with a higher version, it may not run. On dynamic library named adopt Linux libxxx. so. a. b. c format, including a on behalf of the big version number, b on behalf of the minor version number, c on behalf of the smaller version, we Linux bring cp program, for example, through ldd view its dependence on dynamic libraries


 $ ldd /bin/cp            
linux-vdso.so.1 => (0x00007ffff59df000)
libselinux.so.1 => /lib64/libselinux.so.1 (0x00007fb3357e0000)
librt.so.1 => /lib64/librt.so.1 (0x00007fb3355d7000)
libacl.so.1 => /lib64/libacl.so.1 (0x00007fb3353cf000)
libattr.so.1 => /lib64/libattr.so.1 (0x00007fb3351ca000)
libc.so.6 => /lib64/libc.so.6 (0x00007fb334e35000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007fb334c31000)
/lib64/ld-linux-x86-64.so.2 (0x00007fb335a0d000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fb334a14000)

On the left is the name of the dependent dynamic library, on the right is the file to which the link points, and look at the libacl.so related dynamic library


 $ ll /lib64/libacl.so*           
lrwxrwxrwx. 1 root root 15 1 month  7 2015 /lib64/libacl.so.1 -> libacl.so.1.1.0
-rwxr-xr-x. 1 root root 31280 12 month  8 2011 /lib64/libacl.so.1.1.0

We found that libacl. so. 1 is actually a soft link to the file libacl. so. 1.1.0, named in accordance with our description above. There are some that don't, like


$ ll /lib64/libc.so*            
lrwxrwxrwx 1 root root 12 8 month  12 14:18 /lib64/libc.so.6 -> libc-2.12.so

No matter what the name is, as long as the dynamic library is generated and used in the prescribed way, there will be no problem. And we tend to compile programs on a machine called A, and run programs on a machine called B, in slightly different environments. Let's talk about some of the problems in the generation and use of dynamic libraries

Compilation of dynamic libraries

Let's take a simple program as an example


// filename:hello.c
#include <stdio.h>

void hello(const char* name)
{
 printf("hello %s!\n", name);
}

// filename:hello.h
void hello(const char* name);

Compile using the following command


gcc hello.c -fPIC -shared -Wl,-soname,libhello.so.0 -o libhello.so.0.0.1

The parameter to note is -Wl,soname The -Wl option tells the compiler to pass the following arguments to the linker,
-soname Specifies soname for the dynamic library (simple Shared name, Short for shared object name)

Now we generate libhello.so.0.0.1 when we run ldconfig -n . Command, the current directory will have an additional soft connection


 $ ll libhello.so.0            
lrwxrwxrwx 1 handy handy 17 8 month  17 14:18 libhello.so.0 -> libhello.so.0.0.1

How is the soft link generated? Instead of intercepting the first part of the name libhello.so.0.0.1, it is generated according to -soname specified at compile time, libhello.so.0.0.1. In other words, when compiling the dynamic library, the name specified by -soname has been recorded in the binary data of the dynamic library. . No matter whether the program according to libxxx so. a. b. c format, but almost all Linux dynamic libraries are specified at compile time - soname, we can check my soname through readelf tools, such as the article two dynamic libraries listed in the beginning


 $ readelf -d /lib64/libacl.so.1.1.0                     

Dynamic section at offset 0x6de8 contains 24 entries:
Tag Type    Name/Value
0x0000000000000001 (NEEDED)  Shared library: [libattr.so.1]
0x0000000000000001 (NEEDED)  Shared library: [libc.so.6]
0x000000000000000e (SONAME)  Library soname: [libacl.so.1]

You can see that the last line SONAME is libacl.so.1, so /lib64 has a soft connection like this

If you look at the libc-2.12.so file, it's not named the way we said it would be named


 $ readelf -d /lib64/libc-2.12.so                     

Dynamic section at offset 0x18db40 contains 27 entries:
Tag Type    Name/Value
0x0000000000000001 (NEEDED)  Shared library: [ld-linux-x86-64.so.2]
0x000000000000000e (SONAME)  Library soname: [libc.so.6]

You can also see that the last line, SONAME, is libc.so.6. Even if the dynamic library is not named by version number, there is still a soft link to the dynamic library, and the name of the soft link is the name specified by soname

So the key is this soname, which is equivalent to an intermediary. When our dynamic library just updates a small version, we can make its soname the same, and the executable only recognizes the dynamic library specified by soname. In this way, executable programs that rely on this dynamic library can use the features of the new dynamic library without recompiling

Compilation of executable programs

Again, using the hello dynamic library as an example, let's write a simple program


// filename:main.c
#include "hello.h"

int main()
{
 hello("handy");
 return 0;
}

The directory now has the following structure


 ├ ─ ─  hello.c
 ├ ─ ─  hello.h
 ├ ─ ─  libhello.so.0 -> libhello.so.0.0.1
 ├ ─ ─  libhello.so.0.0.1
 └ ─ ─  main.c

libhello.so.0.0.1 is the dynamic library generated by our compilation. libhello.so.0 is the link generated by ldconfig, and main.c is compiled using the following command


 $ ll /lib64/libacl.so*           
lrwxrwxrwx. 1 root root 15 1 month  7 2015 /lib64/libacl.so.1 -> libacl.so.1.1.0
-rwxr-xr-x. 1 root root 31280 12 month  8 2011 /lib64/libacl.so.1.1.0
0

hello dynamic library cannot be found. Under Linux, specify -lhello at compile time. The linker will look for files like libhello.so. Create such a soft chain, directory structure as follows


 ├ ─ ─  hello.c
 ├ ─ ─  hello.h
 ├ ─ ─  libhello.so -> libhello.so.0.0.1
 ├ ─ ─  libhello.so.0 -> libhello.so.0.0.1
 ├ ─ ─  libhello.so.0.0.1
 └ ─ ─  main.c

Let libhello.so link to the actual dynamic library file libhello.so.0.0.1, and then compile the main program


gcc main.c -L. -lhello -o main

The executable is then generated. Through the above tests, we found that when compiling an executable program, the linker will look for files such as libxxx.so that it relies on, so libxxx.so must be guaranteed to exist

View its dependent dynamic libraries with ldd


 $ ll /lib64/libacl.so*           
lrwxrwxrwx. 1 root root 15 1 month  7 2015 /lib64/libacl.so.1 -> libacl.so.1.1.0
-rwxr-xr-x. 1 root root 31280 12 month  8 2011 /lib64/libacl.so.1.1.0
3

We found that the name of the dynamic library that main program relies on is libhello.so.0, which is neither libhello.so nor libhello.so.0.0.1. There are several steps in the process of generating the main program

The linker compiles the command -L.-lhello to find the libhello.so file in the current directory Read the actual file to which the libhello.so link points, libhello.so.0.0.1 Read SONAME in libhello.so.0.0.1, libhello.so.0 Record libhello.so.0 into the binary data of the main program

So libhello.so.0 is already stored in the binary data of the main program, and the dynamic library that the program looks at via ldd is libhello.so.0, right

And why does ldd show libhello.so.0 as not found, because ldd looks for the file in the path specified by the environment variable $LD_LIBRARY_PATH, and we specify the environment variable to run as follows


 $ ll /lib64/libacl.so*           
lrwxrwxrwx. 1 root root 15 1 month  7 2015 /lib64/libacl.so.1 -> libacl.so.1.1.0
-rwxr-xr-x. 1 root root 31280 12 month  8 2011 /lib64/libacl.so.1.1.0
4

The execution of an executable program

Now test the directory results as follows


 $ ll /lib64/libacl.so*           
lrwxrwxrwx. 1 root root 15 1 month  7 2015 /lib64/libacl.so.1 -> libacl.so.1.1.0
-rwxr-xr-x. 1 root root 31280 12 month  8 2011 /lib64/libacl.so.1.1.0
5

Here we're mixing the compile environment with the run environment, but that's okay, as long as we know how it works, we can figure it out

We've already looked at the main program's dependent dynamic libraries through ldd and specified the LD_LIBRARY_PATH variable, and now we're ready to run


 $ ll /lib64/libacl.so*           
lrwxrwxrwx. 1 root root 15 1 month  7 2015 /lib64/libacl.so.1 -> libacl.so.1.1.0
-rwxr-xr-x. 1 root root 31280 12 month  8 2011 /lib64/libacl.so.1.1.0
6

It seems to be going well. So if we're going to deploy the runtime, how are we going to deploy it? Obviously, the source code is not needed, we just need dynamic libraries and executable programs. Here create a new run directory, and copy the relevant files, directory structure as follows


 ├ ─ ─  libhello.so.0.0.1
 └ ─ ─  main

This is what main will notice


 $ ./main                        
./main: error while loading shared libraries: libhello.so.0: cannot open shared object file: No such file or directory

An error was reported that the libhello.so.0 file could not be found, which means that the file name of the dynamic library that the program needs to look for at runtime is actually SONAME specified at the time of compilation of the dynamic library, which is also the same as the 1 we see with ldd. through ldconfig -n . Create a link, as follows


 $ ll /lib64/libacl.so*           
lrwxrwxrwx. 1 root root 15 1 month  7 2015 /lib64/libacl.so.1 -> libacl.so.1.1.0
-rwxr-xr-x. 1 root root 31280 12 month  8 2011 /lib64/libacl.so.1.1.0
9

Run the program again, and the results will be as expected

According to the above test, the program does not need to know libxxx.so when running, but SONAME of the dynamic library recorded by the program itself, so the running environment of main program only needs the above three files

Dynamic library version updates

Suppose the dynamic library needs to make one small change, as follows


// filename:hello.c
#include <stdio.h>

void hello(const char* name)
{
 printf("hello %s, welcom to our world!\n", name);
}

Because of the small change, we still specify the same soname when compiling the dynamic library


gcc hello.c -fPIC -shared -Wl,-soname,libhello.so.0 -o libhello.so.0.0.2

Copy the new dynamic library to the run directory, which has the following structure


 ├ ─ ─  libhello.so.0 -> libhello.so.0.0.1
 ├ ─ ─  libhello.so.0.0.1
 ├ ─ ─  libhello.so.0.0.2
 └ ─ ─  main

At this point there are two versions of the dynamic library in the directory, but libhello.so.0 points to the old version, run ldconfig -n . Later we found that the link pointed to the new version, as follows


 ├ ─ ─  libhello.so.0 -> libhello.so.0.0.2
 ├ ─ ─  libhello.so.0.0.1
 ├ ─ ─  libhello.so.0.0.2
 └ ─ ─  main

Rerun program


 $ ./main                        
hello Handy, welcom to our world!

Using the new dynamic library without recompiling, wonderful!

Also, if our dynamic library changes significantly, a new soname is specified when compiling the dynamic library, as shown below


gcc hello.c -fPIC -shared -Wl,-soname,libhello.so.1 -o libhello.so.1.0.0

Copy the dynamic library file to the run directory and execute ldconfig -n . , the directory structure is as follows


 ├ ─ ─  libhello.so.0 -> libhello.so.0.0.2
 ├ ─ ─  libhello.so.0.0.1
 ├ ─ ─  libhello.so.0.0.2
 ├ ─ ─  libhello.so.1 -> libhello.so.1.0.0
 ├ ─ ─  libhello.so.1.0.0
 └ ─ ─  main

At this time, it was found that a new link libhello. so. 1 was generated, while the main program still used libhello. so. 0, so it could not use the new version of the dynamic library function and needed to be recompiled

conclusion

In a production environment, programs tend to compile and run separately, but once you understand the mechanics of the series 1 process, you won't be confused by the version of the dynamic library. In short, do it the following way

Specified when compiling a dynamic library -Wl , -soname , libxxx.so.a And set the soname to libxxx. so. a, generate the actual dynamic library file libxxx. so. a. b. c, Compile executable program to ensure libxx. so exists, if it is a soft chain, must point to the actual dynamic library file libxxx. so. a. b. c Run the executable file to ensure libxxx. so. a. b. c file exists, generated by ldconfig libxxx. so. a links to libxxx. so. a. b. c Set the environment variable LD_LIBRARY_PATH and run the executable

Well, the above is the entire content of this article, I hope the content of this article to your study or work can bring 1 definite help, if you have questions you can leave a message to communicate.


Related articles: