• 动态链接库的使用记录


    1. 编译参数

    1.1 -fPIC

    告诉编译器产生与位置无关代码.如果不加-fPIC,则加载.so文件的代码段时,代码段引用的数据对象需要重定位, 重定位会修改代码段的内容,这就造成每个使用这个.so文件代码段的进程在内核里都会生成这个.so文件代码段的copy。每个copy都不一样,取决于这个.so文件代码段和数据段内存映射的位置。不加fPIC编译出来的so,是要再加载时根据加载到的位置再次重定位的.(因为它里面的代码并不是位置无关代码) 如果被多个应用程序共同使用,那么它们必须每个程序维护一份so的代码副本了。

    1.1 -rdynamic

    1、是一个链接器选项,当将所有的*.o和库链接到最终可执行文件中就使用了它。该参数的作用是:将指示连接器把所有符号(而不仅仅只是程序已使用到的外部符号,但不包括静态符号,比如被static修饰的函数)都添加到动态符号表(即.dynsym表)里,以便那些通过dlopen()或backtrace()(这一系列函数使用.dynsym表内符号)这样的函数使用。

    2 动态链接库使用函数如下

    1. //编译时候要加入 -ldl (指定dl库)
    2. //包含的头文件
    3. #include
    4. void *dlopen(const char *filename, int flag);
    5. //dlopen用于打开指定名字(filename)的动态链接库,并返回操作句柄
    6. //参数filename是共享库文件的路径,可以是相对路径或绝对路径。参数flag用于指定打开方式,常用的取值包括RTLD_NOW(立即解析所有符号)、RTLD_LAZY(懒加载,只有当使用时才解析符号)等。
    7. mode: 参数必须包括以下两个值中的一个
    8. RTLD_LAZY 暂缓决定,等有需要时再解出符号
    9. RTLD_NOW 立即决定,返回前解除所有未决定的符号。
    10. mode也可以通过以下零或多个值进行或运算设置
    11. RTLD_LOCAL
    12. RTLD_GLOBAL 允许导出符号
    13. RTLD_GROUP
    14. RTLD_WORLD
    15. void *dlsym(void *handle, const char *symbol);
    16. //根据动态链接库操作句柄与符号,返回符号对应的地址。使用这个函数不但可以获取函数地址,也可以获取变量地址。handle是由dlopen打开动态链接库后返回的指针,symbol就是要求获取的函数或全局变量的名称.
    17. int dlclose(void *handle);
    18. //用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。
    19. char *dlerror(void);
    20. //当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功。

    3. 动态库函数的使用demo记录

    3.1 动态库demo的头文件和源文件 

    3.1.1 libdemo.h头文件

    1. #ifndef _LIBDEMO_H_
    2. #define _LIBDEMO_H_
    3. #include
    4. typedef struct
    5. {
    6. int val;
    7. }Val_t;
    8. extern void add(Val_t* addval);
    9. extern int getVal(void);
    10. #endif

    3.1.2  libdemo.c 文件

    1. #include "libdemo.h"
    2. int g_libValue = 0;
    3. void add(Val_t *addval)
    4. {
    5. g_libValue += addval->val;
    6. }
    7. int getVal(void)
    8. {
    9. return g_libValue;
    10. }

    3.1.3 makefile 简易编写

    1. src=$(wildcard ./*.c) #把所有以.c文件 匹配上,并把文件名提取出来,作为一个列表赋值给src
    2. object=$(patsubst %.c,%.o,$(src)) #将src里的每个文件都由.c替换成.o
    3. target1=libdemo0.so #库文件
    4. target2=libdemo1.so
    5. CC=gcc
    6. CFLAGS=-I./ -shared -fPIC #头文件参数、动态链接编译参数
    7. all:$(target1)
    8. $(target1):$(object)
    9. $(CC) -o $@ $^ $(CFLAGS) #生成动态库文件
    10. cp $(target1) $(target2) #拷贝一个一样的动态库
    11. #参数解释, $@表示目标文件
    12. #参数解释, $^表示所有的依赖文件
    13. #参数解释, $<表示第一个依赖文件
    14. %.o:%.c
    15. $(CC) -o $@ -c $< $(CFLAGS) #生成obj文件
    16. .PHONY:clean
    17. clean:
    18. rm -f $(target1) $(target2) $(object) #清除动态库文件和obj文件

    3.2 应用层调用头文件和源文件

    3.2.1 appldemo.h头文件

    1. #ifndef _APPL_DEMO_H_
    2. #define _APPL_DEMO_H_
    3. #include "libdemo.h"
    4. //调用动态库操作函数
    5. typedef struct
    6. {
    7. void (*p_add)(Val_t*);
    8. int (*p_getval)(void);
    9. } SharedObjOps_t;
    10. extern int SharedObjInit(int id, SharedObjOps_t*op);
    11. #endif

    3.2.2 appldemo.c源文件

    1. #include
    2. #include
    3. #include
    4. #include
    5. #define FILE_PATH_NAME "../lib/libdemo"
    6. /*
    7. * brif :调用动态库初始化函数
    8. */
    9. int SharedObjInit(int id, SharedObjOps_t*op)
    10. {
    11. char filePathName[128] = FILE_PATH_NAME;
    12. char idnum[10] = {0};
    13. char filetype[10] = ".so";
    14. char file[128] = {0};
    15. void *handle; //库文件句柄
    16. strcat(file, filepath);
    17. sprintf(idnum, "%d", id);
    18. strcat(file, idnum);
    19. strcat(file, filetype);
    20. handle = dlopen(file, RTLD_LAZY); //打开动态库,且为暂缓决定,等有需要时再解出符号
    21. if (handle == NULL)
    22. {
    23. return 1; //打不开库
    24. }
    25. op->p_add= dlsym(handle, "add");
    26. op->p_getval= dlsym(handle, "getval");
    27. if(!op->p_add || !op->p_getval)
    28. {
    29. return 2; //找不到其中的库函数
    30. }
    31. return 0;
    32. }
    33. int main()
    34. {
    35. SharedObjOps_t op0, op1; //两个动态库操作函数结构体句柄
    36. Val_t val0 = {0}, val1 = {0};
    37. //分别初始化两个动态库
    38. if(SharedObjInit(0, &op0))
    39. {
    40. return 1; //失败
    41. }
    42. if(SharedObjInit(1, &op1))
    43. {
    44. return 1; //失败
    45. }
    46. val0.val = 10;
    47. val0.val = 20;
    48. op0.p_add(&val0);
    49. op1.p_add(&val1);
    50. printf("op0's g_libValue returned: %d\n", op0.p_getval());
    51. printf("op1's g_libValue returned: %d\n", op1.p_getval());
    52. val0.val = 1;
    53. val1.val = 2;
    54. op0.p_add(&val0);
    55. op1.p_add(&val1);
    56. printf("op0's g_libValue returned: %d\n", op0.p_getval());
    57. printf("op1's g_libValue returned: %d\n", op1.p_getval());
    58. return 0;
    59. }

    3.2.3  Makefile编写

    1. src=$(wildcard ./*.c)
    2. object=$(patsubst %.c,%.o,$(src))
    3. target=appdemo
    4. CC=gcc
    5. CFLAGS=-I./ -I../lib -ldl
    6. all:$(target)
    7. $(target):$(object)
    8. $(CC) -o $@ $^ $(CFLAGS)
    9. %.o:%.c
    10. $(CC) -o $@ -c $< $(CFLAGS)
    11. .PHONY:clean
    12. clean:
    13. rm -f $(target) $(object)

  • 相关阅读:
    RpcProvider的网络服务,以及怎么发布服务方法
    (笔记整理未完成)【字符串算法:Trie树】
    Linux下Jenkins服务器安装与使用
    jenkins安装与插件管理
    umi4中的配置问题,我想用umirc.ts中alias配置没起作用。是我的用法不对吗?
    谷歌最新版本下载最新驱动网址chrome driver Version: 122.0.6261.111
    CListCtrl设置只显示单列
    测试/开发程序员的思考,突破变得更强......
    Chrome速度惊人,不到30天修复40个漏洞
    nginx热备配置
  • 原文地址:https://blog.csdn.net/weixin_44419248/article/details/133562200