一.为何要有编译连接的过程
原因:程序文件需要运行环境,机器不识别高级语言
Linux下可执行文件是ElF、Windows下可执行文件是PE
编译连接过程:
预编译 生成.i文件
1.删除#idefine 文本替换
2.#if #endif #elif
3.#include 展开头文件
4.添加行号和文件标识 用于编译器产生调试用的行号信息及用于产生编译错误和警告显示行号
5.不处理#pragma
编译 生成.s文件
1.词法分析
2.语法分析
3.语义分析
4.代码优化volatile关键字禁止代码优化,多线程中会出现问题
5.生成汇编指令
汇编 生成.o文件
1.翻译指令
汇编完成后遗留的问题
1.强弱符号(仅存在于C语言) 初始化和未初始化
2.符号表 外部符号
3.指令段 虚假的地址和偏移(此时还没有完成地址映射所以分配的是虚拟地址)
链接 生成.exe文件
1.合并段和符号 在链接之前都是在单个源文件,整个项目是多个源文件,将多个源文件内容合并
2.符号解析
3.分配地址和空间
4.符号的重定位 原本的地址为虚拟地址,现在合并后将真实的符号地址赋予
程序经过编译链接还是不可以运行,最终运行的是进程
链接前的文件虚拟地址都为0
程序加载到内存运行过程:
程序 - 虚拟空间 - 内存 - (寄存器or缓存) - CPU
1.首先创建内核映射结构体并建立虚拟地址空间和物理内存的映射
2.加载指令和数据
3.把入口地址写入下一行指令寄存器
Q:为何不将程序直接加载到内存中呢?
A:加了虚拟地址空间,将程序与程序之间分开,保护每个程序的安全,独立性
2.虚拟地址空间布局
ZONE_DMA 直接内存访问区,不经过寄存器
ZONE_NORMAL 与页面的映射关系
ZONE_HIGHMEM 大于1G文件的映射
问题:
以上的变量存放在何处?
.data(数据段)
gdata1 全局变量并且已经初始化
gdata4 静态全局变量且已经初始化
data1 静态局部变量且已经初始化
.bss:
gdata2 全局变量但初始化为0
gdata3 全局变量但未初始化 无法区分强弱符号 故在符号表中标记为COM*(弱符号)*
gdata5 静态全局变量初始化为0
gdata6 静态全局变量但未初始化
data2 静态局部变量初始化为0
data3 静态局部变量但未初始化
.text(指令段)
data4 局部变量已经初始化
data5 局部变量初始化为0
data6 局部变量未初始化
包括函数符号
对于.bss段解释:为未初始化的全局变量和静态局部变量预留位置,它并没有内容,所以也不占据空间。
为何不将.data段和.text段合并呢?
1.当程序被装载后,数据和指令分别映射到虚拟内存上,但是数据区域是可读、可写的,指令段仅仅是可读,这样操作可以限制程序的指令的更改。
2.考虑到CPU的缓存,缓存会提升CPU与内存的数据交换,所以尽可能让缓存的命中率提高,当数据段和指令段分开后形成指令缓存、数据缓存,缓存的命中率也就提升了。
3.共享指令,当系统中运行多个程序的副本,它们的指令都是一样的,那么内存中仅须保存一份程序的指令部分。
函数的开栈
1.压入实参 自右向左
2.压入下一行指令的地址
3.压入调用方函数的栈底指针寄存器的值
4.跳转到被调用方函数栈帧
5.被调用方开辟局部变量活动的空间并初始化CCCC CCCC
函数的返回值
<=4 eax寄存器带回
<=8 >4 两个寄存器 eax、edx
>8 临时量
函数重载
释义:同一接口 不同形态
Bool Compare(int, int) (1)
Bool compare(double, double) (2)
C语言下生成的函数符号
_Compare (1)
_Compare (2)
C++下生成的函数符号
函数原型:函数的返回值 函数名 形参
不能作为函数重载依据
形参:1.个数2.类型3.顺序
重载发生条件:同一作用域下,函数名一致,形参列表不同
调用重载函数的三种可能:
- 编译器找到一个与实参最佳匹配的函数,生成调用函数的代码。
- 找不到任何一个函数与调用的实参匹配,编译器发处无匹配的错误信息
- 多个函数匹配,但无最佳匹配,发生错误,(二义性调用)