C语言中内存分布及程序运行加载过程
一个程序内存分配:
下图是APUE中的一个典型C内存空间分布图(虚拟内存)
C语言中内存分布及程序运行加载过程
例如:
include
int g1=0, g2=0, g3=0;
int max(int i)
{
int m1=0,m2,m3=0,p_max;
static n1_max=0,n2_max,n3_max=0;
p_max = (int)malloc(10);
printf("打印max程序地址\n");
printf("in max: 0xx\n\n",max);
printf("打印max传入参数地址\n");
printf("in max: 0xx\n\n",&i);
printf("打印max函数中静态变量地址\n");
printf("0xx\n",&n1_max); //打印各本地变量的内存地址
printf("0xx\n",&n2_max);
printf("0xx\n\n",&n3_max);
printf("打印max函数中局部变量地址\n");
printf("0xx\n",&m1); //打印各本地变量的内存地址
printf("0xx\n",&m2);
printf("0xx\n\n",&m3);
printf("打印max函数中malloc分配地址\n");
printf("0xx\n\n",p_max); //打印各本地变量的内存地址
if(i) return 1;
else return 0;
}
int main(int argc, char **argv)
{
static int s1=0, s2, s3=0;
int v1=0, v2, v3=0;
int p;
p = (int)malloc(10);
printf("打印各全局变量(已初始化)的内存地址\n");
printf("0xx\n",&g1); //打印各全局变量的内存地址
printf("0xx\n",&g2);
printf("0xx\n\n",&g3);
printf("======================\n");
printf("打印程序初始程序main地址\n");
printf("main: 0xx\n\n", main);
printf("打印主参地址\n");
printf("argv: 0xx\n\n",argv);
printf("打印各静态变量的内存地址\n");
printf("0xx\n",&s1); //打印各静态变量的内存地址
printf("0xx\n",&s2);
printf("0xx\n\n",&s3);
printf("打印各局部变量的内存地址\n");
printf("0xx\n",&v1); //打印各本地变量的内存地址
printf("0xx\n",&v2);
printf("0xx\n\n",&v3);
printf("打印malloc分配的堆地址\n");
printf("malloc: 0xx\n\n",p);
printf("======================\n");
max(v1);
printf("======================\n");
printf("打印子函数起始地址\n");
printf("max: 0xx\n\n",max);
return 0;
}
打印结果:
可以大致查看整个程序在内存中的分配情况:
可以看出,传入的参数,局部变量,都是在栈顶分布,
随着子函数的增多而向下增长.
函数的调用地址(函数运行代码)(高地址)
而malloc分配的堆则存在于这些内存之上,并向上生长
全局变量,静态变量都是在分配内存的低部存在(低地址)
程序如何装载的
1 编译:
C语言中内存分布及程序运行加载过程
2 编译结果:
C语言中内存分布及程序运行加载过程
file a.out 查看文件类型
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=0xd66ac36636c4fcfcbe395efb6bbd38c053e1c6c7, not stripped
ELF目标文件格式的最前端是ELF****文件头(****ELF Header****),
包含了描述整个文件的基本属性,如ELF版本、目标机器型号、程序入口地址等
3 加载:
图1做了简单的说明(Linux系统下的)
C语言中内存分布及程序运行加载过程
左边的是UNIX/LINUX系统的执行文件,右边是对应进程逻辑地址空间的划分情况。
我理解就是类似mmap函数 直接内存映射
1 ELF****文件头 指定加载入口地址
2 加载 代码段 数据段 其他部分
参考
1 Linux内核如何装载和启动一个可执行程序
http://www.cnblogs.com/bushifudongjing/p/5361805.html
2 <程序员的自我修养—链接、装载与库.pdf>