1、编译链接运行原理
(1)预编译:
a、删除所有的“#define”,并扩展所有的宏定义.
b、处理所有的预编译指令,如“#if”,“#endif”,“#ifdef”等.
c、处理所有的“#include”预编译指令,并把包含的文件插入到该预编译指令所在的位置中.
d、删除所有的注释.
e、添加行号和文件名标识,以便于编译器产生调试用的符号信息和编译时出现编译错误或警告时显示行号.
f、保留所有的“#pragma”预编译指令,因为编译器编译时会需要他们。
(2)编译:词法分析、语法分析、语义分析、代码优化、生成汇编指令
(3)汇编:将代码文件翻译成二进制文件,生成符号表,生成各个section
(4)链接:
a、合并各个section,调整section的起始位移和段大小
b、合并符号表(外部符号),进行符号解析
c、分配地址和空间
d、符号重定位:符号重定位要解决的是当前编译单元如何访问「外部」符号这个问题
(5)运行
a、建立虚拟地址空间和物理内存的映射(创建映射结构体 PCB)
b、加载指令和数据
c、入口地址写入下一行指令寄存器
2、虚拟地址空间布局
4G的虚拟内存空间:
其中1G是属于内核空间,另外的3G属于用户空间
所有的进程都拥有属于自己的用户空间,但却共享一个内核空间
现在我们从上向下开始分析
首先是用户空间:
①:128M大小的不可访问区域(保留区)
我们通常将申请的临时指针变量初始化时置为NULL,可以防止后续无意使用这个指针出错,因为NULL == 0x0,将其指针指向0x0这个地址时,因为0x0这个地址属于保留区,没有访问权限的。
②:.text代码段
这个区域存储的是代码中的指令。用来存放代码的地方(.text段),不可修改,存放在只读区域内。
指令:一份代码是由数据和指令构成的,除数据外剩下的都叫做指令,另外,局部变量也属于指令,但是局部变量存储在栈上,代码运行时才在栈中预留好的区域中开辟。
③:.data数据段
这个区域存储的是代码中的各种数据,包括全局变量,静态局部变量,但两者必须为已初始化且初始化不为零的数据。
④:.bss段
这个区域存储也是代码中的各种数据,不过存储的是未初始化的和已经初始化为0的全局变量和已经初始化为0的静态局部变量(static)