骚操作:利用强弱符号制作插件库

开发 前端
没有链接插件库时,由于其函数地址为0,因此,我们程序内判断,if(xxx),当地址为0时,执行默认的行为语句。

[[384132]] 

本文转载自微信公众号「编程珠玑」,作者守望先生。转载本文请联系编程珠玑(ID:shouwangxiansheng)公众号。

在《什么是强符号和弱符号》中简单介绍了强弱符号,那么强弱符号的性质有什么用呢?

还记得在《什么是强符号和弱符号》中提到的链接原则吗?

  • 当有强符号和弱符号时,选择使用强符号

那么我们正可以利用这个原则做以下事情:

  • 定义为弱符号,如果是弱符号,使用默认行为
  • 如果链接了库,是强符号,则使用外部定义行为

以此来实现一个类似插件的功能。通俗一点说:

  • 当没有插件时,使用默认行为
  • 链接了插件时,使用插件的功能

原理和示例

其原理也非常简单:

  • 外部引用弱符号
  • 如果符号地址为0,则说明外部没有链接插件库,未有强符号,走默认流程
  • 如果符号地址不为0,则说明链接了插件库,执行插件库的功能。

示例程序如下:

  1. // 来源:公众号【编程珠玑】 
  2. // 作者:守望先生 
  3. #include<stdio.h> 
  4. __attribute__((weak)) void my_print(); 
  5.  void test_print() 
  6.     // 如果是强符号,说明链接了外部插件,使用外部定义 
  7.     if(my_print) 
  8.     { 
  9.         my_print(); 
  10.     } 
  11.     else 
  12.     { 
  13.         // 弱符号,走默认逻辑 
  14.         printf("this is weak print\n"); 
  15.     } 
  16. int main(void) 
  17.     test_print(); 
  18.     return 0; 

上面的test_print函数是弱符号,在没有其他地方定义的情况下,也是能够正常编译运行的:

  1. $ gcc -o main main.c 
  2. $ ./main 
  3. this is weak print 

观察可执行文件:

  1. $ nm main |grep my_print 
  2.            w my_print 

通过nm命令我们也可以知道test_print是弱符号,它前面的修饰字符是W,代表weak。

插件库

前面的示例程序已经能否工作了,如何让它能否支持插件库呢?或者说,如何让它支持外部的插件功能呢?

关于制作库(静态库或动态库制作可以参考《手把手教你制作静态库》)

这里以静态库为例:

  1. // print_plugin.c 
  2. #include<stdio.h> 
  3. void my_print() 
  4.     printf("this is plugin print\n"); 

制作静态库:

  1. $ gcc -c print_plugin.c 
  2. $ ar -rcs libprint_plugin.a print_plugin.o 

链接插件库

现在重新编译main程序,并使用插件库:

  1. $ gcc -o main main.c -L./ -lprint_plugin 
  2. $ gcc  -o main  main.c  -L. -Wl,--whole-archive -lprint_plugin -Wl,--no-whole-archive 
  3. $ nm main |grep my_print 
  4. 000000000000067a T my_print 
  5. $ ./main 
  6. this is plugin print 

需要注意的是,这里在链接插件库之前,需要加上:

  1. -Wl,--whole-archive 

该选项会将插件库中所有符号都链接进来,若非如此,在main.c中已经有了my_print符号,将不会链接进来,而在此之后,又要将该选项恢复。最终我们可以通过nm命令看到my_print符号已经不再是W了。也就看到了最后:

  1. this is plugin print 

的打印了。

也就实现了我们所谓插件的功能,换句话说,可以对目标程序进行功能的裁剪或者增加。

总结

由于以下几点原因,我们可以自己做一些支持插件库的程序:

1.重复强弱符号同存在时,使用强符号

2.弱符号链接不存在时,不会报错

3.未链接的外部符号,地址为0,可通过判断避免访问非法地址

再结合前面的例子分别解释一下:

1.这一点在《什么是强符号和弱符号》一文中已经有解释说明了

2.在开始的程序中,即便没有链接插件库,程序也可以正常编译链接通过,而不会报错

3.没有链接插件库时,由于其函数地址为0,因此,我们程序内判断,if(xxx),当地址为0时,执行默认的行为语句。

 

责任编辑:武晓燕 来源: 编程珠玑
相关推荐

2024-11-13 16:19:12

2022-07-27 08:24:44

数据库RTOSQL

2021-04-19 09:15:14

老板公司企业

2020-11-16 07:15:41

Linux权限管理

2019-05-23 14:59:21

PythonPDF编程语言

2018-11-30 09:30:46

aiohttp爬虫Python

2022-08-18 15:03:13

并发编程

2020-11-16 11:50:21

Python代码命令

2021-06-08 07:04:45

Service Mes微服务熔断

2022-04-25 08:43:47

pandas代码Python

2011-07-05 18:04:45

QT Mysql

2021-08-26 05:03:18

内存机制磁盘

2021-12-14 09:12:40

Gopher结构体接口

2020-03-11 20:11:06

电脑骚操作AMD

2020-04-27 20:55:42

JavaJava 8编程语言

2023-12-21 14:43:30

Python字典

2021-08-05 18:21:29

Autowired代码spring

2020-11-23 11:30:00

IDEA技巧开发

2021-11-03 17:04:11

拦截器操作Servlet

2020-04-03 13:43:23

Python列表推导式字典推导式
点赞
收藏

51CTO技术栈公众号