返回介绍

5. 动态库

发布于 2024-10-12 21:58:10 字数 3081 浏览 0 评论 0 收藏 0

动态库文件独立存在,在程序启动后被动态链接器(ld-linux-x86-64.so)加载。

  • 所用接口未变的情况下,更新动态库,无需重新编译调用程序。

创建

准备好库源码文件(.c)以及包含原型的头文件(.h)。

使用 -shared -fPIC 生成动态库。

代码优化发生在编译阶段,链接时不会再次优化,所以要区分 debug 和 release 版本。可分别提供 lib<name>.solib<name>_release.so 两个版本。

$ gcc -g -O0 -Wall -shared -fPIC -o libdemo.so *.c

使用

如生成的库文件不存放到系统目录下,需以 -Wl,-rpath 参数向链接器传递一到多个新搜索路径(冒号分隔)。这些路径将嵌入到可执行文件内。

注意:链接参数要放在 *.c 后面。

$ gcc -g -O0 -I./lib -o test  *.c  -L./lib -Wl,-rpath=./:./lib -ldemo
                              ~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

由于添加了 ././lib 搜索路径,所以 libdemo.so 可放在这两个相对目录下。如果库文件移动到其他目录(或非当前工作目录),无需重新链接,命令行以 LD_LIBRARY_PATH 指定即可。

$ ldd ./test
	linux-vdso.so.1 (0x00007ffe88fd7000)
	libdemo.so => ./lib/libdemo.so (0x00007f6595b2c000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6595936000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f6595b38000)
 $ LD_LIBRARY_PATH=./xxx ldd ./test
	linux-vdso.so.1 (0x00007ffc575df000)
	libdemo.so => ./xxx/libdemo.so (0x00007f105677e000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1056588000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f105678a000)

插件

还可像插件(plugin)那样在运行期动态装载。

// add.c

#include <stdio.h>

int add (int x, int y)
{
    return x + y;
}
$ gcc -shared -fPIC -o libadd.so add.c

$ nm libadd.so
00000000000010f9 T add

使用 dlopen 载入,然后通过符号查找并获取指针。

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

int main (void)
{
    // 载入动态库。
    void *handle = dlopen("./lib/libadd.so", RTLD_LAZY);
    if (handle == NULL) 
    {
        puts(dlerror());
        return -1;
    }

    // 函数指针变量。
    int (*add)(int, int);

    // 获取符号地址。
    add = dlsym(handle, "add");
    if (add == NULL)
    {
        puts(dlerror());
        return -1;
    }

    // 执行后关闭。
    printf("%d\n", add(11, 22));
    dlclose(handle);

    return 0; 
}
$ gcc -o test main.c -ldl

$ ./test
33

技巧

为动态库添加一个初始化(init)函数,在载入时执行。

// init.c  放在其他文件也可。

#include <stdio.h>

static void __attribute__ ((constructor)) lib_init (void);
 
static void lib_init (void) 
{ 
    printf("Library ready.\n");
    return;
}

向链接器传递 -Wl,--entry=<func> 设置入口,让动态库可直接执行。

动态链接器路径和文件名,可用 ldd 查看其他程序。

const char service_interp[] __attribute__((section(".interp"))) \
			= "/lib64/ld-linux-x86-64.so.2";

void lib_entry (void)
{
    printf("hello, world!\n");
    exit(0);
}
$ gcc -shared -fPIC -o libdemo.so -Wl,--entry=lib_entry *.c
$ ./libdemo.so
hello, world!

Shared libraries with GCC on Linux

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文