Linux 进程空间,内存四区里都是些什么东西

按32位的Linux系统,对于一个进程,其0-3G的用户空间分布如下图所示:

进程空间


从低地址到高地址,一般分为:

  1. 代码段。顾名思义就是一些代码,当然也包括 函数。
  2. 只读数据段。主要存的是 只读数据,包括字符串常量、初始化的const全局常量,初始化的const static常量。这些值初始化后不能够被改变,即使通过指针也不可以,否则会 出现段错误。
  3. 初始化数据段。主要存储的是初始化的的非const类型的 全局变量和初始化的 static变量。
  4. 未初始化数据段。包括未初始化的或初始化为0的全局变量和static变量,包括const修饰的全局变量和static变量。const类型变量可以通过指针改变。未初始化数据都是0。
  5. 堆。malloc申请的空间。
  6. 加载动态库区。
  7. 栈。
  8. 普通局部变量。
  9. 指向命令行参数及环境变量的指针。
  10. 命令行参数和环境变量。

下面就用代码显示哪种数据存储在哪个区段,以更好的理解进程空间。建议在32位Linux系统上测试。

(由于加载动态库区的地址不知道怎么获得,暂且放弃。)

#include<stdio.h>
#include<stdlib.h>
int GlobleInit = 10;
int GlobleNoInit;
int GlobleInit0 = 0;

int GlobleNoInArr[10];
int GlobleInArr[10] = {1,2,3};

static int StaticGlobleIn = 3;
static int StaticGlobleNoIn;

const static int CStaticGlobleIn = 2;
const static int CStaticGlobleNoIn;

const int ConstGloble = 1;
const int ConstGlobleNoIn;

int Func(void);
int Func2(int a);
int Func3(int a);

int main(int argc, char *argv[], char *env[])
{
	int i = argc-1;

	printf("env[%d] =	%p	%s\n",0,env[0],env[0]);//环境变量

	for(; i>=0;i--){		//命令行参数
		printf("argv[%d] =	%p	%s\n",i,argv[i],argv[i]);
	}
	printf("&env[%d] =	%p\n",0,&env[0]);		//环境变量
	for(i = argc-1; i>=0;i--){	//命令行参数
		printf("&argv[%d] =	%p\n",i,&argv[i]);
	}

	printf("&env	=	%p\n",&env);	//环境变量
	printf("&argv	=	%p\n",&argv);	//命令行参数
	printf("&argc	=	%p\n",&argc);	//命令行参数个数
    
	Func2(2);

	register registerPart = 10;	//register 变量不能获取地址
    
	const int ConstPart1 = 2;	//0xbfc3ce68变量为什么按相反的顺序入桟
	int Stack = 38;			//0xbfc3ce6c
	int StackNoIn;			//0xbfc3ce6c
	const int ConstPart2 = 2;	//0xbfc3ce70

	static int StaticPartIn20 = 20;
	static int StaticPartIn = 22;
	static int StaticPartIn21 = 21;
	static int StaticPartNoIn;

	static int StaticPartInArr[128] = {1};
	static int StaticPartNoInArr[128];

	const static int CStaticPartIn = 2;
	const static int CStaticGPartNoIn;

	int *Heap = (int*)malloc(sizeof(int)*100);
	FILE *fp = fopen("aaa","r+");
	if(fp == NULL)
		return -1;
	fgetc(fp);
    //局部变量,栈
	printf("&ConstPart2	=	%p\n",&ConstPart2);
	printf("&Stack	=		%p\t%d\n",&Stack,Stack);
	printf("&StackNoIn	=	%p\t%d\n",&StackNoIn,StackNoIn);
	printf("&ConstPart1	=	%p\n",&ConstPart1);
    //堆
	printf("_IO_buf_base	=	%p\n",fp->_IO_buf_base);
	printf("Heap	=		%p\n",Heap);
    //未初始化数据段
	printf("&GlobleNoInit	=	%p\t%d\n",&GlobleNoInit,GlobleNoInit);
	printf("&GlobleNoInArr	=	%p\t[0]=%d\n",GlobleNoInArr,GlobleNoInArr[0]);
	printf("&CStaticGPartNoIn  =	%p\n",&CStaticGPartNoIn);
	printf("&ConstGlobleNoIn =	%p\n",&ConstGlobleNoIn);
	printf("&StaticPartNoIn	=	%p\n",&StaticPartNoIn);
	printf("StaticPartNoInArr  =	%p\n",StaticPartNoInArr);
	printf("&StaticGlobleNoIn  =	%p\n",&StaticGlobleNoIn);
	printf("&CStaticGlobleNoIn  =	%p\n",&CStaticGlobleNoIn);
	printf("&GlobleInit0	=	%p\t%d\n",&GlobleInit0,GlobleInit0);
    //初始化数据段
	printf("StaticPartInArr	=	%p\n",StaticPartInArr);
	printf("&StaticPartIn20	=	%p %d\n",&StaticPartIn20,StaticPartIn20);
	printf("&StaticPartIn	=	%p\n",&StaticPartIn);
	printf("&StaticPartIn21	=	%p %d\n",&StaticPartIn21,StaticPartIn21);
	printf("&StaticGlobleIn  =	%p\n",&StaticGlobleIn);
	printf("&GlobleInit	=	%p\n",&GlobleInit);
	printf("&GlobleInArr	=	%p\t[0]=%d\n",GlobleInArr,GlobleInArr[0]);
    //只读数据段
	printf("&CStaticPartIn  =	%p\n",&CStaticPartIn);
	printf("\"asdfg\"		=	%p\n","asdfg");
	printf("&ConstGloble	=	%p\n",&ConstGloble);
	printf("&CStaticGlobleIn  =	%p\n",&CStaticGlobleIn);
    //代码段
	printf("&Function	=	%p\n",Func);
	printf("&main		=	%p\n",main);

	fclose(fp);
	free(Heap);
	return 0;
}
int Func(void){
	static int StaticPartInFunc = 22;
	static int StaticPartNoInFunc;
	printf("StaticPartNoInFunc =	%p\n",&StaticPartNoInFunc);
	printf("StaticPartInFunc =	%p\n",&StaticPartInFunc);
}
int Func2(int a){
	int PartInFunc = 22;
	int PartNoInFunc;
	printf("PartNoInFunc 	=	%p\n",&PartNoInFunc);
	printf("PartInFunc 	=	%p\n",&PartInFunc);
}
int Func3(int a){
}

将代码编译后生成‘a.out’可执行文件,在用'readelf -S a.out '获得一些内存空间地址的信息,如下:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
    ... ...
  [11] .init             PROGBITS        08048370 000370 00002e 00  AX  0   0  4
  [13] .text             PROGBITS        08048430 000430 00060c 00  AX  0   0 16
  [14] .fini             PROGBITS        08048a3c 000a3c 00001a 00  AX  0   0  4
  [15] .rodata           PROGBITS        08048a58 000a58 00032c 00   A  0   0  4
    ... ...
  [24] .data             PROGBITS        0804a020 001020 00028c 00  WA  0   0 32
  [25] .bss              NOBITS          0804a2c0 0012ac 00028c 00  WA  0   0 32

将a.out执行后输出如下:

env[0] =	0xbfa59404	MANPATH=/opt/Qt5.3.1//man:
argv[0] =	0xbfa593fe	a.out
&env[0] =	0xbfa5899c
&argv[0] =	0xbfa58994
&env	=	0xbfa58908
&argv	=	0xbfa58904
&argc	=	0xbfa58900

PartNoInFunc =	0xbfa588ac
PartInFunc 	=	0xbfa588a8
&ConstPart2	=	0xbfa588e0
&Stack	=		0xbfa588d8	38
&StackNoIn	=	0xbfa588dc	-1218888107
&ConstPart1	=	0xbfa588d4

_IO_buf_base  =	0xb7718000//fopen函数文件默认缓冲区地址
Heap	=		0x8bb0008

&GlobleNoInit	=	0x804a548	0
&GlobleNoInArr	=	0x804a520	[0]=0
&CStaticGPartNoIn =	0x804a2f0
&ConstGlobleNoIn =	0x804a500
&StaticPartNoIn	=	0x804a2f4
StaticPartNoInArr =	0x804a300
&StaticGlobleNoIn =	0x804a2e4
&CStaticGlobleNoIn= 0x804a2e8
&GlobleInit0	=	0x804a2e0	0
.bss    0x804a2c0
StaticPartInArr	=	0x804a0a0
&StaticPartIn20	=	0x804a2a0 20
&StaticPartIn	=	0x804a2a4
&StaticPartIn21	=	0x804a2a8 21
&StaticGlobleIn  =	0x804a088
&GlobleInit	  =  	0x804a040
&GlobleInArr	=	0x804a060	[0]=1
.data   0x804a020
&CStaticPartIn  =	0x8048d80
"asdfg"		=       0x8048cdb
&ConstGloble	=	0x8048a64
&CStaticGlobleIn  =	0x8048a60
.rodata 0X8048a58
&Function	=   	0x804891f
&main		=   	0x80484e4
.text   0X8048430

最后在说说为什么会有未初始化数据段呢?请跳转下面到连接:

C语言全局未初始化数据段分析 http://blog.csdn.net/candcplusplus/article/details/12576185

弱符号与强符号概念 http://www.cnblogs.com/whos/archive/2010/10/20/1856274.html

然后我还要补充一下。未初始化数据段的数据在编译完生成可执行文件后,只是在文件中占了个位置,并没有任何数据在文件中存有真实数据。

#include<stdio.h>
int arr[1000] = {0};
const int glob;
int main(){
	return 0;
}
-rwxrwxr-x 1 oracle oracle<span style="font-family: Arial, Helvetica, sans-serif;"> </span>7163  9月 21 19:09 a.out

#include<stdio.h>
int arr[1000] = {1};
const int glob;
int main(){
	return 0;
}
-rwxrwxr-x 1 oracle oracle<span style="font-family: Arial, Helvetica, sans-serif;"> </span>11211  9月 21 19:12 a.out
显然位初始化数据的执行文件要小。







猜你喜欢

转载自blog.csdn.net/u013411873/article/details/48677851