POSIX 动态链接库 API

更新时间:
2024-05-13
下载文档

POSIX 动态链接库 API

动态库常用 API

加载动态库

#include <dlfcn.h>
void  *dlopen(const char *pcFile, int  iMode);

函数 dlopen 原型分析:

  • 此函数成功时返回模块句柄,失败时返回 NULL 并设置错误号。
  • 参数 pcFile 是动态库文件名。
  • 参数 iMode 以掩码形式表示库的加载属性。

调用 dlopen 函数将按指定的 iMode 打开一个动态库。SylixOS 加载器会检测 pcFile 是否为路径,如果是则加载该路径对应的文件,否则在动态库文件搜索路径中查找名称为 pcFile 的文件,动态库文件搜索路径见 下载动态库 章节。

SylixOS 打开动态库模式包括:RTLD_GLOBAL 和 RTLD_LOCAL,其中 RTLD_GLOBAL 表示模块为全局模块,需要注意的是,只有全局模块能导出符号到内核符号表;RTLD_LOCAL 表示局部模块。

查找符号

#include <dlfcn.h>
void  *dlsym(void  *pvHandle, const char *pcName);

函数 dlsym 原型分析:

  • 此函数成功时返回符号地址或者 NULL,失败时返回 NULL 并设置错误号。
  • 参数 pvHandle 是模块句柄,由 dlopen 函数返回。
  • 参数 pcName 是被查找的符号名称。

调用 dlsym 函数将从 pvHandle 动态库文件中返回 pcName 代表的函数地址,如果 pcName 不存在,则返回 NULL,因此不应该从返回值来判断 dlsym 函数是否成功,可以通过调用 dlerror 函数获得错误信息。

卸载动态库

#include <dlfcn.h>
int  dlclose(void  *pvHandle);

函数 dlclose 原型分析:

  • 此函数成功返回 0,失败返回-1 并设置错误号。
  • 参数 pvHandle 为模块句柄,由 dlopen 函数返回。

调用 dlclose 函数将减少 pvHandle 动态库的引用计数,如果引用计数减到零并且没有符号被引用,则卸载该动态库。

获取错误信息

#include <dlfcn.h>
char *dlerror(void);

函数 dlerror 原型分析:

  • 返回带有错误信息的字符串。

调用 dlerror 函数将返回调用 dlopen 函数、dlsym 函数和 dlclose 函数的错误信息,如果没有错误,则返回 NULL。

下面程序展示加载动态库的方法。

#include <stdio.h>
#include <dlfcn.h>
int main (int argc, char *argv[])
{
    void     *so_handler;
    void    (*sub_fun)();
    fprintf(stdout, "Hello World!\n");
    so_handler = dlopen("libsubfun.so", RTLD_GLOBAL);
    if (!so_handler) {
        fprintf(stderr, "%s \n",dlerror());
        return (-1);
    }
    sub_fun = dlsym(so_handler, "lib_func_test");
    if (!sub_fun) {
        fprintf(stderr, "%s \n",dlerror());
        return (-2);
    }
    sub_fun();
    dlclose(so_handler);
    return (0);
}
#include <stdio.h>
void lib_func_test (void)
{
    fprintf(stdout, "hello library lib_func_test() run!\n");
}

在 SylixOS Shell 下运行程序,运行结果如下:

# ./Load_Dynamic_Library
Hello World!
hello library lib_func_test() run!

其他 API

下面函数可获取比指定地址小的且离指定地址最近的符号信息。

#include <dlfcn.h>
int  dladdr(void *pvAddr, Dl_info *pdlinfo);

函数 dladdr 原型分析:

  • 此函数成功返回大于 0 的值,失败返回 0 并设置错误号。
  • 参数 pvAddr 为符号地址。
  • 输出参数 pdlinfo 返回符号信息,以下是它的成员信息。

调用 dladdr 函数将返回 pvAddr 地址的信息,该信息由 Dl_info 结构体类型返回,该结构体,如下所示:

typedef struct {
const char        *dli_fname;
void               *dli_fbase;
const char         *dli_sname;
void               *dli_saddr;
} Dl_info;

下面是 Dl_info 结构成员含义:

  • dli_fname:表示模块文件路径。
  • dli_fbase:表示模块的加载地址。
  • dli_sname:表示符号名称。
  • dli_saddr:表示符号地址。

dladdr 函数一般用于错误定位时的程序栈信息打印。

下面程序展示了如何利用 dladdr 函数进行栈回溯。

#include <dlfcn.h>
#include <execinfo.h>
#include <stdio.h>
#include <string.h>
#define BT_SIZE 100
void print_backtrace()
{
    Dl_info        info;
    int              nptrs;
    int              i;
    int              ret;
    void        *ptr_buffer[BT_SIZE];
    nptrs = backtrace(ptr_buffer, BT_SIZE);         /* 获取回溯栈信息          */
    for (i = 1; i < nptrs; i++) {                   /* 去掉本函数帧打印         */
        ret = dladdr(ptr_buffer[i], &info);         /* 获取该帧符号信息        */
        if (ret == 0) {
            break;
        }
        fprintf(stdout, "module:%s, function:%s, address:%p\n",
                 info.dli_fname, info.dli_sname, info.dli_saddr);
        if (strcmp(info.dli_sname, "main") == 0) {
            break;
        }
    }
}
void func_test2 (void)
{
    print_backtrace();                                /* 打印栈信息                 */
}
void func_test1 (void)
{
    func_test2();
}
int main (int argc, char *argv[])
{
    func_test1();
    return (0);
}

在 SylixOS Shell 下运行程序,运行结果如下:

# ./Stack_Backtracking
module:/apps/pSuite/Chapter19_DynamicLoading/Stack_Backtracking, function:main, address:0xc00084c4
文档内容是否对您有所帮助?
有帮助
没帮助