Compile dynamic library in Linux environment

Continue to create, accelerate growth! This is the 10th day of my participation in the "Nuggets Daily New Plan · June Update Challenge", click to view the details of the event

We have previously compiled the libstar.a static library for use by zeus (Zeus) and poseidon (Poseidon). Since the static library will copy the content into the program, it will increase the disk storage space.

If there are 100 softwares that use a certain library, if this library is statically linked to 100 software, the amount of data will be very large, so some underlying libraries of the operating system are provided to the upper-level program calls in the form of dynamic libraries .

And the dynamic library also has the advantage that it is easy to update a dynamic library independently, and you can use the mechanism of the dynamic library to make a plug-in system.

How do we compile the libstar.so dynamic library? This is the focus of this article.

The related files sun.c , moon.c and earth.c are still in the  universe  directory before, the extraction code: mku9. Use the following command to compile the libstar.so dynamic library.

gcc -c -o sun.o sun.c
gcc -c -o moon.o moon.c
gcc -c -o earth.o earth.c 
gcc -fPIC -shared -o libstar.so sun.o moon.o earth.o
复制代码

-fPIC is a compilation option, PIC is the abbreviation of Position Independent Code, which means to generate position independent code. The execution result is as follows:

linux-c-shared-1-1


Now use objdump to view the assembly code of this dynamic library.

objdump -d libstar.so > star-so-dump.txt
复制代码

linux-c-shared-1-1-1

As can be seen from the above figure, the dynamic library is not the same as the previous static library, and the addresses of the two calls have been corrected. Why is this? Not to say dynamic linking, it will only be linked at runtime.

Why is the address of the call corrected at this moment?

Note that  moon_rotate@plt the full name of the plt behind is Procedure Linkage Table, we can see where the following callq 590 will jump, as follows:

linux-c-shared-1-1-1-1

The 590 in the above figure is the offset in the hard disk file, and the same binary content can be seen with an offset of 590 bytes. The three assembly instructions in the figure above are not actually the instructions of the moon_rate function we defined earlier.

这个实际上是生成 动态库的时候,给call 00 00 00 的函数引用封装一层。通过 gdb 调试会会发现,程序是先 进入 moon_rate@plt ,然后再通过 jmpq 跳转到 真正的 moon_rate 函数。

这个过程可以理解为, 通过 Procedure Linkage Table 表,跳转到真正的函数。


我们再做一个实验,生成 libstar.so 动态库的时候,把 moon.o 删掉,不加入。看看 sun.o 里面对 moon_rate 的引用会不会被修正。

提醒:注意这个 libstar-err.so,这个漏了 moon.o 的动态库后面会用来显示一个错误的情况。

gcc -fPIC -shared -o libstar-err.so sun.o earth.o
复制代码

linux-c-shared-1-1-1-2

从上图可以看到,即使没有 moon.o 依然会被修正。但是 这个 libstar-err.so 是有问题的,可以使用 ldd 加上 -r 选项进行模拟重定位函数,会发现找不到 moon_rorate 函数的实现。

linux-c-shared-1-1-1-3


因为 sun.o 里面调了 printf 函数,所以用 ldd 查看,可以发现 libstar.so 跟 libc.so 已经建立了链接。

linux-c-shared-1-1-2


现在把 libstar.so 拷贝到 zeus 项目,执行以下命令编译。

gcc -c -o zeus.o zeus.c
gcc -o zeus zeus.o libstar.so
./zeus
复制代码

linux-c-shared-1-2

从上图可以看出,虽然可以顺利链接,生成 zeus 文件,但是运行的时候却报找不到 libstar.so 动态库,这是因为 Linux 环境默认不会从当前路径 加载动态库。而 Windows 环境会从当前路径 加载动态库。

那Linux 的加载器会从哪些目录搜索加载动态库呢?业界制定了一个 FHS (File Hierarchy Standard)标准,这个标准规定了一个系统中的系统文件应该如何存放,大部分Linux系统都遵循这个标准。

共享库的存放方式也在这个 FHS 标准里面,标准定义共享库可以放在 /lib , /usr/lib , /usr/local/lib 这 3个目录。所以运行加载动态库的时候,也会在这 3个目录搜索。

But there is a general practice in  /etc/ld.so.conf.d/ adding custom configuration. Let's take a look at  ld.so.conf the contents of the file, as follows:

linux-c-shared-1-3

It was found that he included other files, so we need to create our own configuration file  /etc/ld.so.conf.d/star.conf with the following contents:

# star default configuration
/usr/local/star/lib
复制代码

Then create a directory  /usr/local/star/lib and copy libstar.so to it  /usr/local/star/lib .

At this point, you also need to reload the previous star.conf configuration and execute the command  sudo ldconfig. There is no problem in running zeus again, even if the libstar.so in the current directory is deleted, it can run, because the  /usr/local/star/lib dynamic library is searched from the directory when running.

linux-c-shared-1-4

Above, I directly wrote the full name of the dynamic library for linking. In fact, another more commonly used syntax for linking dynamic libraries is like this. as follows:

gcc -o zeus zeus.o -L/usr/local/star/lib -lstar
复制代码

-L is the search path for the specified library. As a reminder, linking and running loading are two different operations . The path to load was previously  /etc/ld.so.conf.d/star.conf configured in the file. You still need to  -L specify parameters when linking.


Before we generated a libstar-err.so dynamic library, this dynamic library does not have moon.o, what if the zeus project uses this dynamic library? Copy libstar-err.so to  /usr/local/star/libit and execute the following command to compile again.

mv libstar-err.so /usr/local/star/lib
gcc -o zeus-err zeus.o -L/usr/local/star/lib -lstar-err
复制代码

linux-c-shared-1-4-1

It can be seen that the linker reports an error directly and cannot find the function implementation of moon_rotate.


Related Reading:

1. "C++ Static Library and Dynamic Library" - Wu Qin

Guess you like

Origin juejin.im/post/7105383802075119647