初探iptables自动加载模块原理

本文深入探讨iptables自动加载模块的工作原理,从构造函数、析构函数、结构体、GCC编译器以及空指针的角度出发,揭示其内在机制。

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/mogo/2.6.17-x86-old/user/iptables/include -fPIC hello.c

[root@rhce lion]# ./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是怎么用的。
库模块源码:
  1. #include <stdio.h>
  2. #include <match.h>

  3. #define _init __attribute__((constructor)) _INIT

  4. static int hello()
  5. {
  6.         printf("hello called\n");

  7.         return 0;
  8. }

  9. static struct test_match test = {
  10.         .name  = "hello",
  11.         .match = hello
  12. };

  13. void _init(void)
  14. {
  15.         printf("init hello\n");

  16.         register_match(&test);

  17.         return ;
  18. }
复制代码
运行后生成libhello.so文件

主程式动态加载so文件并调用模块的函数
  1. #include <stdio.h>
  2. #include <match.h>
  3. #include <dlfcn.h>

  4. int main()
  5. {
  6.         struct test_match *ptr;

  7.         if (dlopen("./libhello.so", RTLD_NOW) == NULL) {
  8.                 printf("load lib error.\n");

  9.                 return 0;
  10.         }

  11.         ptr = find_match("hello");
  12.         if (ptr) {
  13.                 printf("find match:%s\n", ptr->name);
  14.                 ptr->match();
  15.         }

  16.         return 0;
  17. }
复制代码
编译成可执行文件运行:
  1. [root@rhce netcos]# ./main 
  2. init hello
  3. find match:hello
  4. hello called
复制代码
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值