Linux下编译动态链接库与使用详解

linux下库的简介

两种库

  1. 静态库
  2. 动态库 
    区别:在于代码被载入的时刻不同。静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小

库的存储位置和命名规范

存储:一般放在/usr/lib和/lib下 
命名规范: 
1. 静态库的名字一般为libxxxx.a,其中xxxx是该lib的名称 
2. 动态库的名字一般为libxxxx.so.major.minor,xxxx是该动态库的名称,major是主版本号, minor是副版本号

查看一个可执行程序依赖哪些库 
ldd命令可以查看一个可执行程序依赖的共享库

在新安装一个库之后如何让系统能够找到他 
如果安装在/lib或者/usr/lib下,那么ld默认能够找到,无需其他操作。 
如果安装在其他目录,需要将其添加到/etc/ld.so.cache文件中,步骤如下 
1. 编辑/etc/ld.so.conf文件,加入库文件所在目录的路径 
2. 运行ldconfig,该命令会重建/etc/ld.so.cache文件

编写动态链接库

头文件so.h

#ifndef  SO_H #define  SO_H int add(int a, int b); #endif  /*SO_H*/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

实现文件so.c

#include "so.h" int add(int a, int b)
{ return a + b;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

编译动态链接库

gcc -fPIC -c so.c //生成so.o 
gcc -shared -o libtest.so so.o 
(上面两行可以整合成一行:gcc so.c -fPIC -shared -o libtest.so

  1. -fpic 使输出的对象模块是按照可重定位地址方式生成的(即与位置无关)。
  2. -shared指定把对应的源文件生成对应的动态链接库文件libtest.so文件 
    通过nm -g libtest.so可以看到,导出符号表中已经有add这个符号了:
$ nm -g libtest.so 0000000000000670 T add 0000000000201030 B __bss_start
                 w __cxa_finalize@@GLIBC_2.2.5 0000000000201030 D _edata 0000000000201038 B _end 0000000000000684 T _fini
                 w __gmon_start__ 0000000000000540 T _init
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 w _Jv_RegisterClasses
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

使用动态库

  1. 隐式链接(编译时链接) 
    编写主程序main.c:
#include <stdio.h> #include "so.h" int main(int argc, char *argv[])
{
    printf("%d\n", add(1, 2)); return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

使用gcc main.c -L. -ltest -o test进行编译。

  • -L:添加库文件的搜索路径
  • -l:指定需要链接的库。该名称是处在头lib和后缀.so中的名称,如上动态库libtest.so的l参数为-l test

此时通过readelf test -d已经能看到生成的可执行文件test的Dynamic section里依赖libtest.so了

$ readelf test -d

Dynamic section at offset 0xe18 contains 25 entries:
  Tag Type Name/Value 0x0000000000000001 (NEEDED) Shared library: [libtest.so] 0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
......
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

dynamic symbols中也有一个undefined symbol(add)

$ nm -D test 
                 U add 0000000000601048 B __bss_start 0000000000601048 D _edata 0000000000601050 B _end 00000000004007b4 T _fini
                 w __gmon_start__ 0000000000400578 T _init
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 w _Jv_RegisterClasses
                 U __libc_start_main
                 U printf
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

在执行隐式链接的程序之前要注意设置LD_LIBRARY_PATH环境变量,或者把前面生成的libtest.so复制到系统路径下,否则会找不到动态库。

$ ./test 
./test: error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory

$ export LD_LIBRARY_PATH=.

$ ./test 3
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  1. 显式链接(运行时链接) 
    编写主程序dyn_main.c
#include <stdio.h> #include <dlfcn.h> int main(int argc, char *argv[])
{
    void *dl = NULL; int (*add)(int a, int b);
    dl = dlopen( "./libtest.so", RTLD_LAZY); if( dl == NULL )
    { printf("so loading error.\n"); return 1;
    }
    add = (int(*)(int, int))dlsym(dl, "add"); if( dlerror() != NULL )
    { printf("fun load error.\n"); return 1;
    } printf("%d\n", add(1, 2)); return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

使用gcc dyn_main.c -ldl -o dyn_test编译。

这时通过readelf dyn_test -d可以发现,dyn_test不依赖libtest.so:

$ readelf dyn_test -d

Dynamic section at offset 0xe18 contains 25 entries:
  Tag Type Name/Value 0x0000000000000001 (NEEDED) Shared library: [libdl.so.2] 0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
......
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

dyn_test的dynamic symbols中也没有add:

$ nm -D dyn_test 
                 U dlerror
                 U dlopen
                 U dlsym
                 w __gmon_start__
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 w _Jv_RegisterClasses
                 U __libc_start_main
                 U printf U puts
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

运行程序也不需要设置LD_LIBRARY_PATH环境变量

$ ./dyn_test 3
  • 1
  • 2


原文链接: Linux下编译动态链接库与使用详解 版权所有,转载时请注明出处,违者必究。
注明出处格式:流沙团 ( https://gyarmy.com/post-471.html )

发表评论

0则评论给“Linux下编译动态链接库与使用详解”