gcc 属性 section 在应用层代码的使用¶
@2010-12-02 新版功能: 创建
Linux 内核 init/main.c 里的 do_initcalls 就是利用 gcc 的 section 属性来自动遍历 执行各个模块的初始化代码,从而避免复杂的注册处理。那么,在应用层代码里能否 借用这个方法呢,看下面的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #include <stdio.h>
#include <string.h>
typedef void(*func)();
void func_a()
{
printf("%s:%d\n", __func__, __LINE__);
}
void func_b()
{
printf("%s:%d\n", __func__, __LINE__);
}
static func * const fn_a __attribute__((used, section("init"))) = (func * const)&func_a;
static func * const fn_b __attribute__((used, section("init"))) = (func * const)&func_b;
int main()
{
extern const func __start_init;
extern const func __stop_init;
func *f = (func *)&__start_init;
while (f < (func *)&__stop_init) {
(*f++)();
}
return 0;
}
|
编译运行如下:
# gcc -Wall -O2 a.c && ./a.out
func_a:8
func_b:13
可以看到,func_a 和 func_b 被执行了。这个程序里的 __start_init 和 __stop_init 其实是由链接器生成的,规则是在 section 名前加上 __start_ 和 __stop_。
注意属性 section 前的 used 属性:在这个例子中如果打开优化会出现编译错误,原 因是 fn_a 和 fn_b 由于没有在任何其他地方用到而被优化掉。
不过在打开优化选项时该程序编译不通过,还需要进一步研究。
$ gcc -Wall -O1 a.c && ./a.out
/tmp/ccvxshH3.o: In function `main':
a.c:(.text+0x7): undefined reference to `__start_init'
a.c:(.text+0xc): undefined reference to `__stop_init'
collect2: ld 返回 1
另外采用这种方法执行的函数必须没有依赖关系,尤其对不同源文件中的函数, 其执行顺序由链接器来决定。