标签:
对于可执行文件,它包含了许多的段,例如(数据段,文本段,BSS段等),它们是二进制文件中简单的区域,里面保存了和某种特定类型(如符号表条目)相关的所有信息。
对于一个源文件,哪些地方会放到哪个段,如下图:
可得知,程序代码是存放在文本段,初始化的全局变量和静态变量是存放到数据段中的,而没有初始化的全局变量和静态变量则是存放到BSS,运行时所需要的BSS段的大小记录在目标文件中,但BSS段并不占据目标文件的任何空间,局部变量、临时数据、传递到函数中的参数则是存储于栈中,而通过函数调用malloc动态分配的内存则是在堆中。对于数组的初始化,初始化所用的数据则是放在只读数据段。const修饰的变量也是存放在只读数据段。
而对于一个可执行程序,它的段在内存分布(进程的地址空间)如下:
在上图中,注意虚拟地址空间的最低部分未被映射,它位于进程的地址空间内,但并未赋予物理地址,所以任何对它的引用都是非法的,该段空间用于捕捉使用空指针和小整型值的指针引用内存的情况。
通过编写程序加深理解:
#include <stdio.h>
#define ARRAY_SUM 50
char global_var_data = ‘A‘; //存放在数据段
char global_var_bss; //存放在BSS段
int main(void)
{
static char static_var_data = ‘A‘; //存放在数据段
static char static_var_bss; //存放在BSS段
char stack_var_char; //存放在栈中
char rodata_var_array_char[ARRAY_SUM] = "I AM IN RODATA"; //数组变量stack_var_array位于栈,但字符串常量则位于只读数据段
int rodata_var_array_int[ARRAY_SUM] = {1, 2, 3, 4}; //常量1,2,3,4,0,0...这些都存储在只读数据段
int *heap_var_int = malloc(100); //存放在堆中
char *heap_var_char = malloc(100); //存放在堆中
printf ("global_var_data = %p 存放在数据段\n", &global_var_data);
printf ("static_var_data = %p 存放在数据段\n", &static_var_data);
printf ("global_var_bss = %p 存放在BSS段\n", &global_var_bss);
printf ("static_var_bss = %p 存放在BSS段\n", &static_var_bss);
printf ("heap_var_int = %p 存放在堆中\n", heap_var_int);
printf ("heap_var_char = %p 存放在堆中\n", heap_var_char);
printf ("stack_var_char = %p 存放在栈中\n", &stack_var_char);
printf ("rodata_var_array_char = %p 存放在栈中\n", rodata_var_array_char);
printf ("rodata_var_array_int = %p 存放在栈中\n", rodata_var_array_int);
printf ("\"I AM IN RODATA\" = %p 存放在只读数据段\n", "I AM IN RODATA");
free(heap_var_int);
free(heap_var_char);
return 0;
}
运行结果打印如下:
当考虑到共享库时,进程的地址空间则变成下图所示:
在进行函数调用时,堆栈存储与此有关的一些维护性信息,这些信息称为堆栈结构,或称为过程活动记录。运行时系统维护一个指针(常常位于寄存器中),通常称为fp,用于提示活动堆栈结构。它的值是最靠近堆栈顶部的过程活动记录的地址。对于过程活动记录,它的描述可以见下图:
这里所描述的静态链接是指 指向它的外层函数的活动记录指针,它允许内层过程访问外层过程的活动记录,因此也可以访问外层过程的局部数据。但这仅限于允许函数在函数内部定义的语言当中,而C语言是不允许函数在函数内部定义的,所以它的活动记录中不需要静态链接。
下面是每个函数调用在运行时创建过程活动记录的过程:
但在某些编译器中,可能会把过程活动记录的内容放到寄存器中,这样可以提高函数调用的速度。
标签:
原文地址:http://blog.csdn.net/talent_cyj/article/details/51276832