Linux C 系统编程(12)系统库访问

涉及系统库访问的几个函数有dlopen、dlsym、dlclose、dlerr。这几个函数主要用于加载动态链接库。系统库的出现是为了使程序方便扩展,具备通用性,可以采用插件形式。采用异步事件驱动模型,保证主程序逻辑不变,将各个业务已动态链接库的形式加载进来,这就是所谓的插件。linux提供了加载和处理动态链接库的系统调用,非常方便。


1 dlopen、dlsym、dlclose、dlerror简介方法简介

使用时均需要包含含头文件: 

#include <dlfcn.h> 

1.1 dlopen函数简介

@1 基本定义:打开一个动态链接库

@2 函数定义:

void * dlopen( const char * pathname, int mode ); 
函数描述: 在dlopen的()函数以指定模式打开指定的动态连接库文件,并返回一个句柄给调用进程。
注意:使用时最后需要dlclose()来卸载打开的库。
参数pathname:绝对路径
参数mode:分为这两种
   RTLD_LAZY 暂缓决定,等有需要时再解出符号 
   RTLD_NOW 立即决定,返回前解除所有未决定的符号。 
  RTLD_LOCAL 
  RTLD_GLOBAL 允许导出符号 
  RTLD_GROUP 
  RTLD_WORLD 
返回值:打开错误返回NULL,成功则返回库引用

注意:使用该系列方法时编译时候要加入 -ldl (指定dl库) 

1.2 dlsym函数简介

@1 基本定义:根据动态链接库操作句柄与符号,返回符号对应的地址。

@2 函数定义:

void* dlsym(void* handle,const char* symbol);
函数描述:
dlsym根据动态链接库操作句柄(handle)与符号(symbol),返回符号对应的地址。
使用这个函数不但可以获取函数地址,也可以获取变量地址。
参数handle:由dlopen打开动态链接库后返回的指针,
参数symbol:要求获取的函数或全局变量的名称。
返回值:查找到的对应函数或者变量地址值    

1.3 dlclose函数简介

@1 基本定义,关闭动态库链接的句柄

@2 函数定义:

int dlclose (void *handle);
函数描述:
dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。
参数handle:需要关闭的动态库句柄
返回值:动态库卸载应用计数的返回值

1.4 dlerror函数简介

@1 基本定义:动态库的错误判定与分析

@2 函数定义:

char *dlerror(void);
函数描述:当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功。
返回值:错误信息 或 NULL

2 dlopen、dlsym、dlclose、dlerror使用实例

2.1 动态库测试用例

hello.c函数原型如下:  

#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
typedef struct {
    const char *module;
    int  (*GetValue)(char *pszVal);
    int   (*PrintfHello)();
} hello_ST_API;

int GetValue(char *pszVal)
{
    int retval = -1;
    if (pszVal)
        retval = sprintf(pszVal, "%s", "123456");
        printf("%s, %d, pszVer = %s\n", __FUNCTION__, __LINE__, pszVal);
    return retval;
}

int PrintfHello()
{
    int retval = -1; 
    printf("%s, %d, hello everyone\n", __FUNCTION__, __LINE__);
    return 0;
}

const hello_ST_API  Hello = {
    .module = "hello",
    GetValue,
    PrintfHello,
};

编译的时候用指令:

gcc -fPIC -shared  -o hello.so hello.c

上面的函数是用一个全局结构体hello来指向。在dlsym定义中说不仅可以获取函数的地址,还可以获取全局变量的地址。所以此处是想通过dlsym来获取全局变量的地址(最常见的用法)

2.2 dlopen、dlsym、dlclose、dlerror的使用动态库的实例

#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h>

typedef struct {
    const char *module;
    //int (*GetValue)(char *pszVal);
    int (*PrintfHello)();
} hello_ST_API;

int main(int argc, char **argv)
{
    hello_ST_API *hello;
    int i = 0;
    void *handle;
    char psValue[20] = {0};
 
    handle = dlopen("库存放的绝对路径,你可以试试相对路径是不行的", RTLD_LAZY);
    if (!handle) {
        printf("%s,%d, NULL == handle\n", __FUNCTION__, __LINE__);
        return -1;
    }
    dlerror();
    hello = dlsym(handle, "Hello");
    if (!hello) {
        printf("%s,%d, NULL == handle\n", __FUNCTION__, __LINE__);
        return -1;
    }
    if (hello && hello->PrintfHello)
        i = hello->PrintfHello();
    printf("%s, %d, i = %d\n", __FUNCTION__, __LINE__, i);
    if (hello && hello->GetValue)
        i = hello->GetValue(psValue);
    if (hello && hello->module){
        printf("%s, %d, module = %s\n", __FUNCTION__, __LINE__, hello->module);
    }
    dlclose(handle);
    return 0;
}

编译指令:

gcc -o test hello_dlopen.c -ldl 

特殊说明:dlsym找到全局结构体hello后,可以直接用这个全局结构体指针来使用库里面的函数了,因为我们有时候提供的库不仅仅是一个两个函数的,一般的一个库都会存在多个函数,用这种方式就可以直接使用了。不然找函数名称的话要写好多个dlsym。

发布了289 篇原创文章 · 获赞 47 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/vviccc/article/details/105171704