- 论坛徽章:
- 0
|
本帖最后由 netcos 于 2014-01-26 14:38 编辑
iptables使用dlopen加载动态库,每个库中都定义了void _init(void)函数,在使用dlopen加载库的时候系统会调用_init函数,
在_init函数中调用xtables_register_match对模块进行注册。iptables这种动态加载模块的方式很适合做定制开发,所以我就自己摸索了下。
我自己写了一个测试的例子:
gcc -O2 -Wall -fPIC -c hello.c
gcc -shared -o hello.so hello.o
hello.o: In function `_init':
hello.c:(.text+0x0): multiple definition of `_init'
/usr/lib/gcc/i386-redhat-linux/4.1.1/../../../crti.o:(.init+0x0): first defined here
编译的时候出现了重复定义的错误。这是为什么?
_init是共享库用来初始化全局变量和对象的,在库文件中已经定义过了。有什么办法可以使用_init来初始化我们自己的函数呢?
通过查看iptables的模块代码,发现所有的文件都包含#include <xtables.h>头文件,会不会是xtables.h中动了什么手脚?
在hello.c中包含xtables.h头文件,果然编译通过。
#include <stdio.h>
#include <xtables.h>
int main()
{
return 0;
}
void _init(void)
{
printf("init hello\n");
return ;
}
gcc -O2 -Wall -o hello -I/home/iptables/include -fPIC hello.c
[root@rhce netcos]# ./hello
init hello
xtables.h头文件中到底做了什么呢?
我在代码中看到一个宏定义:# define _init __attribute__((constructor)) _INIT,会不会是这个?
于是在hello.c中去掉头文件xtables.h,将该宏定义换进去,果然没问题。
那这个宏定义是什么意思呢?
用__attribute__((constructor))来定义的函数,表示函数是构造函数,在main执行之前被调用;相应的用__attribute__ ((destructor))析构函数,在main退出时执行。
void _init(void)就相当于是__attribute__((constructor)) _INIT(void),其实不管函数名定义成什么都会被执行到。
自动初始化的问题解决了,现在就来看看dlopen是怎么用的。
库模块源码:
- #include <stdio.h>
- #include <match.h>
- #define _init __attribute__((constructor)) _INIT
- static int hello()
- {
- printf("hello called\n");
- return 0;
- }
- static struct test_match test = {
- .name = "hello",
- .match = hello
- };
- void _init(void)
- {
- printf("init hello\n");
- register_match(&test);
- return ;
- }
复制代码 运行后生成libhello.so文件
主程式动态加载so文件并调用模块的函数- #include <stdio.h>
- #include <match.h>
- #include <dlfcn.h>
- int main()
- {
- struct test_match *ptr;
- if (dlopen("./libhello.so", RTLD_NOW) == NULL) {
- printf("load lib error.\n");
- return 0;
- }
- ptr = find_match("hello");
- if (ptr) {
- printf("find match:%s\n", ptr->name);
- ptr->match();
- }
- return 0;
- }
复制代码 编译成可执行文件运行:- [root@rhce netcos]# ./main
- init hello
- find match:hello
- hello called
复制代码 |
|