Linux下C程序的内存布局

C可执行程序的结构

C程序语言在编译和连接后,生成可执行程序,作为文件存放在磁盘上它的结构如下:

1.代码段Text
2.只读数据段RO Data
3.读写数据段RW Data

其中RO Data和RW Data统称为初始化数据段initialized data
在可执行程序载入运行时,会产生地址映射,以上三部分会对应到程序的虚拟地址空间。
除了以上三个区域外,还产生:

4.未初始化数据段BSS区域
5.Heap区域
6.Stack区域

各部分含义

1.代码段(Code或Text)

从0x08048000虚拟地址开始。代码段由程序中执行的机器代码组成。在C语言中,程序语句进行编译后,形成机器代码。在执行程序的过程中,CPU的程序计数器指向代码段的每一条机器代码,并由处理器依次运行。

2.只读数据段(RO data)

存放const 常量,字符串常量等。使用这些数据的方式类似查表式操作,由于这些变量不需要更改,因此只需要放置在只读存储器中即可。

3.已初始化读写数据段(RW data)

存放已初始化全局变量和static变量,这些变量需要占用存储空间,具有初值,供程序运行时读写。

4.未初始化数据段(BSS)

存放未初始化全局变量和static变量。这些变量在程序运行之前,不占用存储空间。

5.堆(heap)

堆内存只在程序运行时出现,一般由程序员分配和释放,比如malloc.在具有操作系统的情况下,如果程序没有释放,操作系统可能在程序(例如一个进程)结束后回收内存。

6.栈(stack)

0xC0000000开始往下低地址增长。栈内存只在程序运行时出现,在函数内部使用的变量、函数的参数以及返回值将使用栈空间,栈空间由编译器自动分配和释放。
栈大小在linux下可以使用ulimit -s查看,linux默认8M。可以修改,比如:用ulimit -s 4096指定为4M。如果程序用栈太大就出现栈溢出,程序出现段错误并退出。比如无限递归。

示例代码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const char ro[] = {"this is read only data"}; //只读数据区
static char rw_1[] ={"this is global read write data"}; //已初始化读写数据段
char BSS_1[ 100]; //未初始化数据段
const char *ptrconst ="constant data"; //字符串放在只读取数据段
int main()
{
short b; //在栈上,占用2个字节
char a[100]; //在栈上开辟100个字节, 它的值是其首地址
char s[]="abcdefg"; //s在栈上,占用4个字节,"abcdefg"本身放置在只读数据区,占8个字节
char *p1; //p1在栈上,占用4个字节
char *p2="123456"; //p2 在栈上,p2指向的内容不能改,“123456”在只读数据区
static char rw_2[]={"local read write data"};//已初始化读写数据段
static char BSS_2[100]; //未初始化数据段
static int c = 0; //全局(静态)初始化区
p1=(char *)malloc(10 * sizeof(char)); //分配内存区域在堆区
strcpy(p1,"xxxx"); //“XXXX”放在只读数据区,占5个字节
free(p1); //使用free释放p1所指向的内存
return 0;
}

内存布局图