在linux内核代码文件include/linux/init.h文件中,有以下一段注释:
* Don't forget to initialize data not at file scope, i.e. within a function,
* as gcc otherwise puts the data into the bss section and not into the init
* section.
不理解其含义,但这是关于变量初始化、作用域、init节区的问题。做做实验,看看有什么变化:
- [root@node_1892 init_macro]# cat -n init_data.c
-
1 /* shows in which sections varaibles are stored in.
-
2 * globle var, static var, local var. etc...
-
3 */
-
4 #include
-
5 /*shorthand for attribute section*/
-
6 /*
-
7 #ifndef __section
-
8 #define __seciton(s) __attribute__((__section__(#s)))
-
9 #endif
-
10 */
-
11 /* Simple shorthand for a section definition */
-
12 #ifndef __section
-
13 #define __section(s) __attribute__((__section__(#s)))
-
14 #endif
-
15
-
16 #ifdef DEBUG_SECTION
-
17 #define __init __section(.init.text)
-
18 #define __initdata __section(.init.data)
-
19 #define __initconst __section(.init.rodata)
-
20 #define __exitdata __section(.exit.data)
-
21 #define __exit __section(.exit.text)
-
22
-
23 #else /*!DEBUG_SECTION*/
-
24 #define __init
-
25 #define __initdata
-
26 #define __initconst
-
27 #define __exitdata
-
28 #define __exit
-
29
-
30 #endif
-
31
-
32 int g_var_init __initdata= 0x11;
-
33 int g_var __initdata;
-
34
-
35
-
36 static int gs_var_init __initdata = 0x12;
-
37 static int gs_var __initdata;
-
38
-
39 void my_print(void){
-
40 static int s_var_init __initdata =0x13;
-
41 static int s_var __initdata;
-
42 /*statements below avoid unused warnings.*/
-
43 g_var_init = 0;
-
44 g_var = 0;
-
45 gs_var_init = 0;
-
46 gs_var = 0;
-
47 printf("%d, %d, %d, %d, %d, %d\n", g_var_init, g_var, gs_var_init, gs_var, s_var_init, s_var);
-
48 }
-
49 int main(){
-
50 my_print();
-
51 return 0;
-
52 }
-
[root@node_1892 init_macro]#
首先编译为不使用section属性的代码,并查看其最终变量分布情况:
从上面输出可以看到:
.data段位于0x600900 ~ 0x600910范围内,符号data_start、__data_start、_edata分别标志该段的起始结束。
.bss未初始化段位于0x600910 ~ 0x600928范围内,符号__bss_start、_end分别标志该段的起始结束。
所以, 变量g_var_init、gs_var_init、s_var_init.2130等已初始化变量都位于.data段内。
未初始化变量g_var、gs_var、s_var.2131等未初始化变量都位于.bss段内。
.bss段紧挨着.data段,长度为0x18。从上面的readelf输出可以看到,.data和.bss在加载时合并到一个Segment中,这个Segment是可读可写的。.bss段和.data段的不同之处在于,.bss段在文件中不占存储空间,在加载时这个段用0填充占据内存。这可以从下面命令看出:
- [root@node_1892 init_macro]# hexdump -C init
-
000008e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-
000008f0 9e 03 40 00 00 00 00 00 ae 03 40 00 00 00 00 00 |..@.......@.....|
-
00000900 00 00 00 00 11 00 00 00 12 00 00 00 13 00 00 00 |................|
-
00000910 00 47 43 43 3a 20 28 47 4e 55 29 20 34 2e 31 2e |.GCC: (GNU) 4.1.|
-
00000920 32 20 32 30 30 38 30 37 30 34 20 28 52 65 64 20 |2 20080704 (Red |
-
00000930 48 61 74 20 34 2e 31 2e 32 2d 34 34 29 00 00 47 |Hat 4.1.2-44)..G|
.data段的所有数据都已初始化,而.bss段则在文件中不占据任何空间。
启用section属性,查看对应的变量分布情况:
所以,.data段位于内存地址0x900 ~ 0x904范围 ,与文件地址范围相同
.init.data段位于内存地址0x904 ~ 0x91c 范围, 与文件地址范围相同
.bss段位于内存地址0x920 ~ 0x930范围,文件地址范围为0x91c ~ 0x91c, 这可以从.comment段的文件起始地址看出。
因此,.data段内没有变量存储,但仍具有一定内存范围。
.init.data段内存储所有标识__section__属性的变量。
.bss段内没有变量存储,但仍具有一定内存范围,从__bss_start和 _end 标识符可以看出。
另外:__data_start 和 _edata标识范围为0x900 ~ 0x91c,说明这两个标识符标志的是所以不属于.bss段的数据的存储范围。
倾印文件内容,可以看到:
- 000008f0 9e 03 40 00 00 00 00 00 ae 03 40 00 00 00 00 00 |..@.......@.....|
-
00000900 00 00 00 00 11 00 00 00 12 00 00 00 00 00 00 00 |................|
-
00000910 13 00 00 00 00 00 00 00 00 00 00 00 00 47 43 43 |.............GCC|
-
00000920 3a 20 28 47 4e 55 29 20 34 2e 31 2e 32 20 32 30 |: (GNU) 4.1.2 20|
-
00000930 30 38 30 37 30 34 20 28 52 65 64 20 48 61 74 20 |080704 (Red Hat |
整个文件空间内存储了.data段和.init.data段内容,而.bss段则在文件中不占据任何存储空间。
从上面分析可以得出,所有生命周期在程序范围内的变量:
未指定section属性时,如果已初始化,则存入.data段;否则存入.bss段。
如果指定section属性,则无论是否初始化,都存入指定段。未初始化变量不会位于.bss段中。
阅读(7979) | 评论(0) | 转发(1) |