一、
在80386之前是实模式,80386之后是保护模式
所谓的32位、62位是指 ALU的宽度,即一次性能处理最大数据长度(比特为单位)
在Windows操作系统下4G虚拟内存空间是,用户空间:内核空间是1:1
在Linux操作系统下4G虚拟内存空间是,用户空间:内核空间是3:1
Linux4G虚拟地址空间分配大致如下图
图1
.data 已初始化且初始化不为0的数据
.bss 未初始化或初始化为0的数据
局部变量的普通变量是指令(.text)
二、
编译
预编译
生成.i文件 命令:gcc -E main.c -o main.o
1.删除#define
2.递归展开#include文件
3.删除#if0 #endif #elif
4.删除注释(// /**/)
5.添加行,文件表示
6.保留#pragma
编译
生成.s文件 命令:gcc -S main.i -o main.s
1.词法分析
2.语法分析
3.语义分析
4.代码优化
汇编
可重定位,可重入
生成.o文件或.obj文件 gcc -c main.s -o main.o
指令代码翻译成二进制
链接
生成.exe文件
1.合并段和符号表
2.符号解析(在符号引用的地方找到符号定义的地方(只关注全局符号))
3.分配地址和空间
4.符号重定位
三、目标文件的分析
可执行文件格式,Windows下问PE格式,Linux下为ELF格式,它们都是COFF格式的变种。目标文件就是源码编译后但未进行连接的那些中间文件,它跟可执行文件的内容结构很相似,所以一般跟可执行文件格式一起采用一种格式存储。
在此,使用main.c进行分析
编译
输入gcc -c *.c 命令对main.c文件进行编译生成main.o文件
查看目标文件的结构和内容:objdump -h main.o
由此可画出ELF文件的大致结构
我们可以发现在.bss文件中大小为20,但我们的main.c 程序中有6个int 型的数据在.bss段中存放,缺失了一个……
这时我们查看符号表
发现!!!缺失的那个数据 gdata3在*COM*块中
这是因为,
在c中,有强弱符号之分
强符号:已初始化的全局变量
弱符号:未初始化的全局变量
规则:
1.两强(两个同名强):重定义
2.一强一弱:选强符号
3.两弱:选字节较大的
此时函数的入口地址为0x0000 0000
链接
输入命令ld -e main -o run main.o
此时有了入口地址
gdata3此时归属于.bss段了
ps:
修改main.c 添加sum.c
此时gdata、sum处于*UND*块
通过链接
四、运行原理
1.创建虚拟地址空间和物理内存的映射(映射结构体)
2.加载指令数据
查看program header 段
3.第一行指令的地址写入pc寄存器中