让我们通过一个简单的C程序来进行分析。
- 原始demo如下
#include<stdio.h>
//int printf(const char* format, ...);
extern int gdata10;
extern int sum(int,int);
int gdata1 = 84;
int gdata2 = 0;
int gdata3;
static int gdata4 = 11;
static int gdata5 = 0;
static int gdata6;
int main(){
int a =1;
int b =0;
int c;
sum(a,b);
static int static_var =85;
static int static_var1 =0;
static int static_var2;
getchar();
return 0;
}
程序就是指令加数据。
操作系统将程序加载到内存中,产生进程。
对于每个程序,操作系统会分配虚拟地址空间(32位系统虚拟内存大小为2的32次方)
2. 程序的内存分布
如下图所示
内存空间分为用户空间(3G)和内核空间(1G)
从0地址开始的128字节不可访问
栈的增长方向是从高到低
3. 编译
编译期间做的工作:代码优化,汇总所有的符号
符号:数据产生符号,指令产生函数名符号
ELF文件的组成
文件头加各个段组成
文件头:
记录段表的起始位置为208,即d0.
段表里面记录了各个段的起始位置和偏移。
通过objdump -t 打印符号表的内容(obj文件还未进行虚拟地址空间的分配)
引用外部变量和函数
对于外部引用的变量和函数,符号表的状态均为UND(undefine)。需要在链接期进行符号解析, 对符号引用的地方都要找到该符号对应的地方
- 链接
链接做的工作:
将所有相同属性的段进行合并,并调整段偏移和段长度,合并符号表,并进行符号解析
链接的核心就是符号的重定位
链接完成后完成虚拟内存的地址分配
通过查看汇编信息,我们可以看到sum和gdata均设置为有效地址
可执行文件和obj文件的区别
可执行文件以页面方式进行组织
相比obj文件,多一个program header段,用于指示操作系统将哪些东西加载到内存里面去
52+ 32*3
load2个页面。
虚拟地址空间和物理地址都是按照页面进行组织。