Linux 动态库动态加载实例

#ifndef STR_OUT_H
    #define STR_OUT_H
    extern "C" void str_out(const char* str); 
#endif

#include
<stdio.h>
#include "str_out.h"
void str_out( const char* str )
{
    printf( "%s\n", str );
}

#include <stdio.h>
#include <dlfcn.h> // dlopendlsym、dlerrordlclose的头文件
#include <stdlib.h>
#include "str_out.h"

// 此例为动态加载动态库,Makefile中会提到静态如何关联加载
int main()
{
    typedef void (*STROUT)(const char*);

    void * hDynamicLib = 0;
    STROUT fpStrOut = 0;

    // 动态加载动态库名字可以不用前缀lib,静态则一定要加
    hDynamicLib = dlopen("/home/nsc/document/testpro/staticlib/str_out.so", RTLD_LAZY);

    if (0 != hDynamicLib)
    {
        fpStrOut = (STROUT)dlsym(hDynamicLib, "str_out");

        char *szErrInfo = dlerror();

        if (0 == szErrInfo)
        {
            fpStrOut("You're success again!\n"); 
        }
        else
        {
            printf("%s\n", szErrInfo); 
        }

        dlclose(hDynamicLib);
    }
    else
    {
        printf("error: load dynamic library failed!\n");  
    }

    return 0;
}

/ * Makefile */
tdynamicload : main.c str_out.so
         g++ -rdynamic -ldl main.c -o tdynamicload
注:选项 -rdynamic 用来通知链接器将所有符号添加到动态符号表中,
  目的是能够通过使用 dlopen 来实现向后跟踪。
       选项 -ldl 表明一定要将 dllib 链接于该程序,
       不然编译器会报dlopendlsym、dlerrordlclose等找不到

str_out.so : str_out.c str_out.h
         g++ -c str_out.c -o str_out.o
         g++ -Wall -W -shared -fPIC str_out.o -o str_out.so
注:由以上命令生成动态库str_out.so,为了可以静态加载动态库,
       则其动态库命名方式为“lib*.so.*

  在这个命名方式中,第一个*表示动态链接库的库名第二个*通常表示该动态库的版本号
  也可以没有版本号
     –fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时
       是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
       –shared:指明编译成动态库。

函数 描述
dlopen 使对象文件可被程序访问
dlsym   获取执行了 dlopen 函数的对象文件中的符号的地址
dlerror  返回上一次出现错误的字符串错误
dlclose 关闭目标文件

 该过程首先是调用 dlopen,提供要访问的文件对象和模式。调用 dlopen 的结果是稍候要使用的对象的句柄。mode 参数通知动态链接器何时执行再定位。有两个可能的值。第一个是 RTLD_NOW,它表明动态链接器将会在调用 dlopen 时完成所有必要的再定位。第二个可选的模式是 RTLD_LAZY,它只在需要时执行再定位。这是通过在内部使用动态链接器重定向所有尚未再定位的请求来完成的。这样,动态链接器就能够在请求时知晓何时发生了新的引用,而且再定位可以正常进行。后面的调用无需重复再定位过程。

还可以选择另外两种模式,它们可以按位 OR 到 mode 参数中。RTLD_LOCAL 表明其他任何对象都无法使加载的共享对象的符号用于再定位过程。如果这正是您想要的的话(例如,为了让共享的对象能够调用原始进程映像中的符号),那就使用 RTLD_GLOBAL 吧。

dlopen 函数还会自动解析共享库中的依赖项。这样,如果您打开了一个依赖于其他共享库的对象,它就会自动加载它们。函数返回一个句柄,该句柄用于后续的 API 调用。dlopen 的原型为:#include <dlfcn.h>

void *dlopen( const char *file, int mode );

 有了 ELF 对象的句柄,就可以通过调用 dlsym 来识别这个对象内的符号的地址了。该函数采用一个符号名称,如对象内的一个函数的名称。返回值为对象符号的解析地址:void *dlsym( void *restrict handle, const char *restrict name );

如果调用该 API 时发生了错误,可以使用 dlerror 函数返回一个表示此错误的人类可读的字符串。该函数没有参数,它会在发生前面的错误时返回一个字符串,在没有错误发生时返回 NULL:char *dlerror();

 最后,如果无需再调用共享对象的话,应用程序可以调用 dlclose 来通知操作系统不再需要句柄和对象引用了。它完全是按引用来计数的,所以同一个共享对象的多个用户相互间不会发生冲突(只要还有一个用户在使用它,它就会待在内存中)。任何通过已关闭的对象的 dlsym 解析的符号都将不再可用。char *dlclose( void *handle );


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值