dlopen动态链接库操作

来源:互联网 发布:数据恢复最好的软件 编辑:程序博客网 时间:2024/06/07 06:42
void *dlopen(const char *filename, int flag);   //打开一个动态链接库,并返回动态链接库的句柄char *dlerror(void);void *dlsym(void *handle, const char *symbol);  //根据动态链接库操作句柄与符号,返回符号对应的地址int dlclose(void *handle);

glibc还增加了两个POSIX标准中没有的API:

  • dladdr,从函数指针解析符号名称和所在的文件
  • dlvsym,与dlsym类似,只是多了一个版本字符串参数

初始化(initializing)和终止化(finalizing)函数

void _init(void);void _fini(void);
  1. 当一个库通过dlopen()动态打开或以共享库的形式打开时,如果_init在该库中存在且被输出出来,则_init函数会被调用。如果一个库通过dlclose()动态关闭或因为没有应用程序引用其符号而被卸载时,_fini函数会在库卸载前被调用
  2. 当使用你自己的_init和_fini函数时,需要注意不要与系统启动文件一起链接。可以使用GCC选项 -nostartfiles 做到这一点
  3. 但是,使用上面的函数或GCC的-nostartfiles选项并不是很好的习惯,因为这可能会产生一些意外的结果。相反,库应该使用attribute函数属性来输出它的构造函数和析构函数
void __attribute__((constructor)) x_init(void)void __attribute__((destructor)) x_fini(void)

例一:

//主程序 main.c//申明结构体typedef struct __test {    int i;    void (* echo_fun)(struct __test *p);}Test;//供动态库使用的注册函数void __register(Test *p) {    p->i = 1;    p->echo_fun(p);}int main(void) {    void *handle = NULL;    char *myso = "./mylib.so";    if((handle = dlopen(myso, RTLD_NOW)) == NULL) {        printf("dlopen - %sn", dlerror());        exit(-1);    }    return 0;}
//动态库 mylib.c//申明结构体类型typedef struct __test {    int i;    void (*echo_fun)(struct __test *p);}Test;//申明注册函数原型void __register(Test *p);static void __printf(Test *p) {    printf("i = %d\n", p->i);}//动态库申请一个全局变量空间//这种 ".成员"的赋值方式为c99标准static Test config = {    .i = 0,    .echo_fun = __printf,};//加载动态库的自动初始化函数void _init(void) {    printf("init\n");    //调用主程序的注册函数    __register(&config);}
# gcc main.c -ldl -rdynamic# gcc -shared -fPIC -nostartfiles -o mylib.so mylib.c

gcc参数 -rdynamic 用来通知链接器将所有符号添加到动态符号表中(目的是能够通过使用 dlopen 来实现向后跟踪).
gcc参数 -fPIC 作用: 当使用.so等类的库时,当遇到多个可执行文件共用这一个库时, 在内存中,这个库就不会被复制多份,让每个可执行文件一对一的使用,而是让多个可执行文件指向一个库文件,达到共用. 宗旨:节省了内存空间,提高了空间利用率

例二:

//主程序 main.cint main(int argc, char **argv){    void *handle;    void (*callfun)();    char *error;    handle = dlopen("/root/tmp/hello.so",RTLD_LAZY);  //如果hello.so不是在LD_LIBRARY_PATH所申明                                                      //的路径中必须使用全路径名    if(!handle)    {        printf("%s \n",dlerror());        exit(1);    }    callfun = (void(*)())dlsym(handle,"hello");    //为函数指针赋值    if(callfun == NULL)    {        printf("%s \n",dlerror());        exit(1);    }    callfun();                          //调用    dlclose(handle);
//动态库 hello.cvoid hello(void){    printf("hello\n");}
# gcc main.c -ldl# gcc -shared -fPIC -o hello.so hello.c

例三:

//动态链接库依赖了主程序中的symbolint day (int a);int life(int a){    return day(a)+8;}
int day(int a){   printf("this is day function\n");   return a+2;}int main(int argc, char **argv) {   void *handle;   int (*life)(int a);   char *error;   handle = dlopen ("liblife.so", RTLD_LAZY);   if (!handle) {       fprintf (stderr, "%s\n", dlerror());       exit(1);   }   dlerror();    /* Clear any existing error */   life  = dlsym(handle, "liblife.so");   if ((error = dlerror()) != NULL)  {       fprintf (stderr, "%s\n", error);       exit(1);   }   printf("%d\n", life(1));   dlclose(handle);   return 0;}
# gcc -shared -fpic -o liblife.so life.c# gcc -rdynamic main.c -ldl
0 0
原创粉丝点击