程序是被分成段加以管理的,在程序被加载到内存中运行之前,各段是放在程序文件中的。
当程序文件中所需的段被加载到内存中后,将通过运行指令来处理相应的数据。有些数据来源于程序文件中的段,有些是自动生成的。
1、段
1.1、指令段
.text 段:
由于处理器只能识别数据和指令。所以不论采用什么高级语言编写程序,都得被编译器转化成为处理器所能识别的数据和机器指令。而编译后的机器指令都被存放在 .text 段。
从 C 源程序角度来看,.text 段中存放的是函数的机器指令实现。
如果处理器有内存管理单元,在可执行程序被加载到内存以后,通常会将 .text 段设置为只读,以防代码不会因为程序出错而被修改。
1.2、数据段
处理器所需加工的数据是放在 .data、.bss 和 .rdata 段的,也可以来自堆和栈。
通过以下,.data 和 .bss 两个数据段所存放数据的区别:
section1.c
#include <stdio.h>
int main()
{
return 0;
}
处
理结果:
[root@localhost huge12]# gcc -g -c section1.c
[root@localhost huge12]# strip section1.o
[root@localhost huge12]# objdump -h section1.o
section1.o: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000019 00000000 00000000 00000034 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000000 00000000 00000000 00000050 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 00000050 2**2
ALLOC
3 .comment 0000002e 00000000 00000000 00000050 2**0
CONTENTS, READONLY
4 .note.GNU-stack 00000000 00000000 00000000 0000007e 2**0
CONTENTS, READONLY
由上可看出,此时在没有任何数据的情况下,.data 和 .bss 段的大小为 0.
section2.c
#include <stdio.h>
int a = 0x77778888
int b = 0;
int main()
{
return 0;
}
处理结果:
[root@localhost huge12]# gcc -g -c section2.c
[root@localhost huge12]# strip section2.o
[root@localhost huge12]# objdump -h section2.o
section2.o: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000019 00000000 00000000 00000034 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000004 00000000 00000000 00000050 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000004 00000000 00000000 00000054 2**2
ALLOC
3 .comment 0000002e 00000000 00000000 00000054 2**0
CONTENTS, READONLY
4 .note.GNU-stack 00000000 00000000 00000000 00000082 2**0
CONTENTS, READONLY
从处理结果:
-
.data 和 .bss 段有了变化,由于在 section2.c 中新增了两个变量,对于初始化不为 0 的变量存放在 .data 段,对于初始化为 0 或 不初始化的全局变量存放在 .data 段。
- .bss 段不存放在程序文件中
- 由于 .bss 段中的变量不需要初始化成特定值(0除外),所以不需要在程序文件中保存其内容,好处是能减小程序文件的大小而节省存储空间
- 对于 .data 段内数据的初始化,是引导加载器加载程序时,通过将程序文件中 .data 段的数据复制到所对应的内存地址空间,从而一次性地完成所有变量的初始化
在一个函数内定义非静态变量(即局部变量)时,变量的内存空间是被分配在栈上的,那么加了 static 后的内存空间与全局变量是一样的。
section3.c
#include <stdio.h>
int main()
{
static int a = 0x77778888;
static int b = 0;
return 0;
}
处理结果:
[root@localhost huge12]# gcc -g -c section3.c
[root@localhost huge12]# strip section3.o
[root@localhost huge12]# objdump -h section3.o
section3.o: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000019 00000000 00000000 00000034 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000004 00000000 00000000 00000050 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000004 00000000 00000000 00000054 2**2
ALLOC
3 .comment 0000002e 00000000 00000000 00000054 2**0
CONTENTS, READONLY
4 .note.GNU-stack 00000000 00000000 00000000 00000082 2**0
CONTENTS, READONLY
下面再来看一看字符串全局变量:
section4.c
#include <stdio.h>
char str[] = "hello world!";
int main()
{
return 0;
}
处理结果:
[root@localhost huge12]# gcc -g -c section4.c
[root@localhost huge12]# strip section4.o
[root@localhost huge12]# objdump -h section4.o
section4.o: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000019 00000000 00000000 00000034 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 0000000d 00000000 00000000 00000050 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 00000060 2**2
ALLOC
3 .comment 0000002e 00000000 00000000 00000060 2**0
CONTENTS, READONLY
4 .note.GNU-stack 00000000 00000000 00000000 0000008e 2**0
CONTENTS, READONLY
下面再对section4.c做一些修改:
#include <stdio.h>
const char str[] = "hello world!";
int main()
{
return 0;
}
处理结果:
[root@localhost huge12]# gcc -g -c section4.c
[root@localhost huge12]# strip section4.o
[root@localhost huge12]# objdump -h section4.o
section4.o: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000019 00000000 00000000 00000034 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000000 00000000 00000000 00000050 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 00000050 2**2
ALLOC
3 .rodata 0000000d 00000000 00000000 00000050 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .comment 0000002e 00000000 00000000 0000005d 2**0
CONTENTS, READONLY
5 .note.GNU-stack 00000000 00000000 00000000 0000008b 2**0
CONTENTS, READONLY
对比你会发现:.rodata 存放的是只读的已初始化变量,与 .data 段不同,对于有内存管理单元的系统, .rodata 段通常也会采用内存管理单元进行只读保护。