使用共享库 | 2套
我们在上一篇文章中介绍了有关共享库的基本信息。在当前文章中,我们将学习如何在 Linux 上创建共享库。
在此之前,我们需要了解程序如何加载到内存中,以及该过程中涉及的各种(基本)步骤。
让我们看一个典型的 C 语言“Hello World”程序。下面给出了简单的 Hello World 程序屏幕图像。
我们使用命令“ gcc -o sample shared.c ”编译我们的代码当我们编译我们的代码时,编译器不会解析函数printf() 的实现。它只验证语法检查。工具链在我们的应用程序中留下了一个存根,它将由动态链接器填充。由于 printf 是标准函数,编译器隐式调用其共享库。更多细节往下看。
我们正在使用ldd列出我们程序二进制映像的依赖项。在屏幕图像中,我们可以看到我们的示例程序依赖于三个二进制文件,即linux-vdso.so.1 、 libc.so.6和/lib64/ld-linux-x86-64.so.2 。
VDSO 文件是系统调用接口和其他一些东西的快速实现,这不是我们的重点(在一些较旧的系统上,您可能会看到不同的文件名代替 *.vsdo.*)。忽略此文件。我们对另外两个文件感兴趣。
文件libc.so.6是各种标准函数的 C 实现。这是我们看到Hello World所需的printf定义的文件。它是需要加载到内存中以运行我们的 Hello World 程序的共享库。
第三个文件 /lib64/ld-linux-x86-64.so.2 实际上是一个在调用应用程序时运行的可执行文件。当我们在 bash 终端上调用程序时,通常 bash 会派生自己并将其地址空间替换为要运行的程序映像(所谓的 fork-exec 对)。内核验证 libc.so.6 是否驻留在内存中。如果没有,它会将文件加载到内存中并重新定位 libc.so.6 符号。然后它调用动态链接器 (/lib64/ld-linux-x86-64.so.2) 来解析应用程序代码的未解析符号(在本例中为 printf)。然后控制权转移到我们的程序main 。 (过程中我有意省略了很多细节,我们的重点是了解基本细节)。
创建我们自己的共享库:
让我们在 Linux 上使用简单的共享库。使用以下内容创建文件library.c 。
文件 library.c 定义了一个函数signum ,我们的应用程序代码将使用它。使用以下命令编译文件 library.c 文件。
gcc -shared -fPIC -o liblibrary.so library.c
标志-shared指示编译器我们正在构建一个共享库。标志-fPIC用于生成位置无关代码(暂时忽略)。该命令在当前工作目录中生成一个共享库liblibrary.so 。我们已经准备好使用我们的共享对象文件(Linux 中的共享库名称)。
使用以下内容创建另一个文件application.c 。
在文件application.c 中,我们调用了在共享库中定义的函数signum。使用以下命令编译 application.c 文件。
gcc application.c -L /home/geetanjali/coding/ -library -o sample
标志-library指示编译器查找当前代码中不可用的符号定义(在我们的例子中是 signum函数)。选项-L提示编译器查看目录,然后是任何共享库的选项(仅在链接时)。该命令生成一个名为“ sample ”的可执行文件。
如果调用可执行文件,动态链接器将无法找到所需的共享库。默认情况下,它不会查看当前工作目录。您必须明确指示工具链提供正确的路径。动态链接器搜索 LD_LIBRARY_PATH 中可用的标准路径,并在系统缓存中搜索(有关详细信息,请探索命令ldconfig )。我们必须将我们的工作目录添加到 LD_LIBRARY_PATH 环境变量中。以下命令执行相同的操作。
导出 LD_LIBRARY_PATH=/home/geetanjali/coding/:$LD_LIBRARY_PATH
您现在可以调用我们的可执行文件,如图所示。
。/样本
我的系统上的示例输出如下所示。
注意:路径/home/geetanjali/coding/是我机器上的工作目录路径。您需要在上述命令中使用的工作目录路径中使用它。
请继续关注,我们甚至还没有探索 1/3 的共享库概念。更高级的概念在后面的文章中。
锻炼:
它是像文章一样的工作簿。除非你练习和做一些研究,否则你不会得到太多。
1.创建类似的例子并在共享库中编写你的won函数。在另一个应用程序中调用该函数。
2. 是否有其他工具可以列出依赖库?
3. 什么是位置无关代码(PIC)?
4. 当前上下文中的系统缓存是什么?目录 /etc/ld.so.conf.d/* 在当前上下文中是如何关联的?