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

另外采用这种方法执行的函数必须没有依赖关系,尤其对不同源文件中的函数, 其执行顺序由链接器来决定。