`
izuoyan
  • 浏览: 9222466 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Linux下动态共享库加载时的搜索路径详解

阅读更多

对动态库的实际应用还不太熟悉的读者可能曾经遇到过类似“error while loading shared libraries”这样的错误,这是典型的因为需要的动态库不在动态链接器ld.so的搜索路径设置当中导致的

具体说来,动态链接器ld.so按照下面的顺序来搜索需要的动态共享库:

1ELF可执行文件中动态段中DT_RPATH所指定的路径。这实际上是通过一种不算很常用,却比较实用的方法所设置的:编译目标代码时,可以对gcc加入链接参数“-Wl,-rpath”指定动态库搜索路径;

2.环境变量LD_LIBRARY_PATH指定的动态库搜索路径;

3/etc/ld.so.cache中所缓存的动态库路径(如果支持ld.so.cache的话)。这可以通过修改配置文件/etc/ld.so.conf中指定的动态库搜索路径来改变;

4.默认的动态库搜索路径/lib

5.默认的动态库搜索路径/usr/lib

嵌入式Linux系统的实际应用中,1和2被经常使用,也有一些相对简单的的嵌入式系统会采用4或5的路径来规范动态库。3在嵌入式系统中使用的比较少,因为有很多系统根本就不支持ld.so.cache。

4和5的方式非常简单,只要将所需要的库放到/lib或/usr/lib就可以解决找不到库的问题,不过对于大一些的系统来说,不太方便管理。1和2的方式要稍微复杂一些,下面我们用一个非常简单的例子来说明如何应用。

首先编写一个最简单的动态共享库,源代码pirnt.c如下:

1 #include <stdio.h>

2

3 void print_foo()

4 {

5 printf("fooooooooo\n");

6 }

注意将它编译成共享库:

# gcc print.c -shared -o libprint.so

# file libprint.so

libprint.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), not stripped

调用该共享库main.c代码如下:

1 #include <stdio.h>

2

3 extern void print_foo();

4

5 int main()

6 {

7 print_foo();

8

9 return 0;

10 }

编译之后的运行结果如下:

# gcc main.c -L./ -lprint -o pfoo

# ./pfoo

./pfoo: error while loading shared libraries: libprint.so: cannot open shared object file: No such file or directory

这便是典型的找不到动态库的错误。通常我们可以通过设置环境变量LD_LIBRARY_PATH来指定动态库的搜索路径(即上面的方法2),比如这样就可以正确运行了:

# export LD_LIBRARY_PATH=./

# ./pfoo

fooooooooo

但这种方法有一个明显的缺点:一旦LD_LIBRARY_PATH被设定,则在这个环境变量生效的范围之内,所有其他的ELF可执行程序也会按照这个顺序去搜索动态库,这样势必会造成搜索时的一些浪费。

我们也可以使用另外一种方案来解决这种问题,即利用参数“-Wl,-rpath”在编译时指定运行时的搜索路径(即上面的方法1),如下所示:

# unset LD_LIBRARY_PATH

# echo $LD_LIBRARY_PATH

# gcc main.c -L./ -lprint -o pfoo_r -Wl,-rpath=./

# ./pfoo

./pfoo: error while loading shared libraries: libprint.so: cannot open shared object file: No such file or directory

# ./pfoo_r

fooooooooo

我们首先unsetLD_LIBRARY_PATH,可以看到它已经不再有效了(当然这不是使用参数“-Wl,-rpath”的必要步骤,在这里只是为了说明它已经不再起作用了),而且”pfoo”程序运行时也会发生找不到库的错误,而我们加入编译参数“-Wl,-rpath,./”之后得到的pfoo_r程序则能正常运行。

事实上我们可以通过readelf工具来查看两个文件的差异:

# readelf -d pfoo

Dynamic segment at offset 0x514 contains 21 entries:

Tag Type Name/Value

0x00000001 (NEEDED) Shared library: [libprint.so]

0x00000001 (NEEDED) Shared library: [libc.so.6]

0x0000000c (INIT) 0x8048344

0x0000000d (FINI) 0x80484e0

0x00000004 (HASH) 0x8048128

0x00000005 (STRTAB) 0x8048240

0x00000006 (SYMTAB) 0x8048170

0x0000000a (STRSZ) 178 (bytes)

0x0000000b (SYMENT) 16 (bytes)

0x00000015 (DEBUG) 0x0

0x00000003 (PLTGOT) 0x80495f8

0x00000002 (PLTRELSZ) 16 (bytes)

0x00000014 (PLTREL) REL

0x00000017 (JMPREL) 0x8048334

0x00000011 (REL) 0x804832c

0x00000012 (RELSZ) 8 (bytes)

0x00000013 (RELENT) 8 (bytes)

0x6ffffffe (VERNEED) 0x804830c

0x6fffffff (VERNEEDNUM) 1

0x6ffffff0 (VERSYM) 0x80482f2

0x00000000 (NULL) 0x0

[root@localhost ldpath]# readelf -d pfoo_r

Dynamic segment at offset 0x518 contains 22 entries:

Tag Type Name/Value

0x00000001 (NEEDED) Shared library: [libprint.so]

0x00000001 (NEEDED) Shared library: [libc.so.6]

0x0000000f (RPATH) Library rpath: [./]

0x0000000c (INIT) 0x8048348

0x0000000d (FINI) 0x80484e4

0x00000004 (HASH) 0x8048128

0x00000005 (STRTAB) 0x8048240

0x00000006 (SYMTAB) 0x8048170

0x0000000a (STRSZ) 181 (bytes)

0x0000000b (SYMENT) 16 (bytes)

0x00000015 (DEBUG) 0x0

0x00000003 (PLTGOT) 0x8049604

0x00000002 (PLTRELSZ) 16 (bytes)

0x00000014 (PLTREL) REL

0x00000017 (JMPREL) 0x8048338

0x00000011 (REL) 0x8048330

0x00000012 (RELSZ) 8 (bytes)

0x00000013 (RELENT) 8 (bytes)

0x6ffffffe (VERNEED) 0x8048310

0x6fffffff (VERNEEDNUM) 1

0x6ffffff0 (VERSYM) 0x80482f6

0x00000000 (NULL) 0x0

readelf -d”可以用来查看ELF文件的动态节(Dynamic Section)。对比pfoo pfoo_r的结果我们可以发现,pfoo_r中多出来了RPATH项,指定”Library rpath: [./]”。通过这种方式,我们可以用非常小的代价(仅增加几乎可以忽略的空间开销),对每个ELF文件都指定最优化的搜索路径,达到提升性能的目的。这是我们比较推荐的一种方法。当然了,具体如果操作依赖于具体的软件系统的情况,简单的系统中直接将所有的库都放到/lib下也未尝不是一种简单易行的优化方案。

分享到:
评论

相关推荐

    嵌入式系统/ARM技术中的Linux下动态共享库加载时的搜索路径详解

    2. **环境变量LD_LIBRARY_PATH**:这是最常见的设置动态库搜索路径的方式,通过设置这个环境变量,可以临时或者持久性地添加额外的搜索路径。然而,这种方法的缺点是它会影响环境中所有使用动态库的程序。 3. **/...

    Linux下Java开发环境搭建以及加载C++动态库方法

    ### Linux 下 Java 开发环境搭建及 C++ 动态库加载方法详解 #### 一、Linux 下 Java 开发背景 Java 作为一种广泛使用的编程语言,其设计初衷是实现一次编写,到处运行的目标,即跨平台特性。这使得 Java 程序能够...

    linux静态库和动态库

    当程序使用动态库时,动态链接的过程如下: 1. **加载ELF映像**:当用户启动一个应用程序时,实际上是加载了一个ELF映像。内核会首先将这个映像加载到用户空间的虚拟内存中。 2. **识别动态链接器**:内核会查找ELF...

    库搜索路径 库搜索路径

    ### 库搜索路径详解 #### 一、概述 在Linux系统中,动态链接库(Dynamic Link Library,简称DLL,在Linux中通常称为共享库)是非常重要的组成部分。为了使程序能够找到并加载所需的动态链接库,系统提供了多种库...

    Linux动态库.txt

    ### Linux动态库详解 #### 一、概述 Linux 动态库是操作系统中不可或缺的一部分,它们使得多个程序能够共享相同的代码段,进而减小程序体积、提高资源利用率。本文将详细介绍 Linux 动态库的基本概念、如何管理和...

    Linux下Gcc生成和使用静态库和动态库详解

    ### Linux下Gcc生成和使用静态库和动态库详解 #### 一、基本概念 **1.1 什么是库** 库本质上是一种可执行代码的二进制形式,它可以被操作系统载入内存执行。无论是Windows还是Linux平台,都广泛地使用着库。然而...

    LINUX下动态链接库的使用

    ### Linux 下动态链接库的使用 #### 一、概述 在 Linux 系统中,动态链接库(Dynamic Link Library,通常以 `.so` 文件扩展名表示)是一种非常重要的概念,它允许开发人员创建可被多个应用程序共享的代码库。通过...

    Linux静态库和动态库

    **Linux库的分类**:Linux下的库主要分为两大类——静态库与动态库,它们的核心区别在于代码的加载时机。静态库在编译阶段即与目标程序结合,而动态库则是在程序运行时动态加载。 #### 静态库与动态库的生成与使用 ...

    linux gcc生成动态库和静态库

    ### Linux GCC 生成动态库与静态库详解 #### 一、基本概念 1.1 **什么是库** 在软件开发领域,库是指预先编写并编译好的一组功能集合,以二进制的形式存在,可供其他程序调用。这些库通常包含了各种预定义的功能...

    linux动态链接机制研究及应用

    这在某些场景下非常有用,例如,当需要在不同的环境中测试相同的应用程序时,或者当需要替换特定版本的共享库时。利用Linux的动态链接机制,可以通过设置环境变量如`LD_LIBRARY_PATH`来实现共享库的重定位。 - **...

    和我一起做Linux动态库

    其中`-fPIC`表示生成位置独立的代码(Position Independent Code),这是创建动态库时必须的,因为动态库中的代码可能在不同的地址空间中加载,位置独立的代码可以适应这种情况。 4. **复制动态库文件**:将生成的...

    Linux静态库和动态库学习总结

    需要注意的是,当使用动态库时,确保`libmylib.so`文件位于可执行文件的同级目录或在`LD_LIBRARY_PATH`环境变量指定的路径中。 #### 七、总结 通过本文的介绍,读者应该对Linux下的静态库和动态库有了更深入的理解...

    动态库的建立

    3. **链接动态库**:在编译主程序时,使用`-L`参数指定动态库的搜索路径,`-l`参数指定需要链接的库名(库名前需加`-l`)。注意,实际链接的动态库文件名中并不包含`lib`前缀和`.so`后缀。 ```shell gcc main.c ...

    动态库的创建和使用——静态加载

    ### 动态库的创建与使用——静态加载 #### 一、基础知识介绍 **动态链接库**(Dynamic Link Library,简称DLL,在Unix/Linux系统中称为**共享对象**或**共享库**,通常以`.so`扩展名命名)是一种可被多个程序同时...

    Linux下目录详解

    ### Linux下目录详解 #### 一、Linux 文件系统与目录结构概述 Linux 是一种高度定制化和可配置的操作系统,其文件系统具有清晰且逻辑性强的目录结构。本篇文章将重点介绍 Red Hat(以 RHEL 5.4 版本为例)下的文件...

    深入探讨Linux静态库与动态库的详解(一看就懂)

    与静态库不同,动态库在编译时并不会被整合到可执行文件中,而是在程序运行时按需加载。这减少了程序的大小,因为多个程序可以共享同一动态库的内存映像。动态库的修改不会影响已编译的程序,使得更新和维护更加便捷...

    linux内核态与用户态内存共享示例

    ### Linux内核态与用户态内存共享示例详解 #### 背景介绍 在Linux系统中,进程间通信(IPC)是常见的需求之一。为了提高效率和灵活性,内核提供了一种机制来允许内核空间与用户空间共享内存区域。这种机制允许用户...

Global site tag (gtag.js) - Google Analytics