这篇博客总结了简单的编译链接到达一个可执行文件的过程的理解。
下面出现的概念都是基于x86体系,32位Linux操作系统下的概念~
一个源代码成为一个可执行文件需要经过编译->链接的过程才能最终生成一个可执行文件,在计算机中运行
*************************************************************************************************************
编译过程:
源文件(*.cpp)
|
预编译(*.i): 这一步主要处理源代码文件中以#开头的预处理指令。包括替换宏、展开预编译指令、删除注释等。
|
编译(*.s): 进行词法、语法分析,生成相应汇编指令
|
汇编(*.o): 将汇编代码代码转变为相应操作系统下的机器指令
|
生成可重定位目标文件:生成可重定位目标文件,
可重定位目标文件的大致布局为:ELF头:描述文件和机器相关信息
.text:代码段
.rodata:只读数据,如c语言中的字符串
.data:已初始化的全局变量
.bss:未初始化的全局变量
.symtab:符号表,存放在程序中定义和引用的函数和全局变量信息,不包含局部变量条目
...
链接过程:
链接通俗来说就是将所有.O文件和库(库中存放着函数的实现)链接起来链接起来。
过程主要分为两步 1)将所有.O文件的段进行合并,其中包含合并符号表,进行符号解析,解析正确后给符号表的符号分配虚拟地址。 2)进行符号重定位
注意:1)在进行文件段合并时,只合并globle的符号,不合并local的符号。
2)符号解析:对未定义的符号,找到其定义的地方。
3)符号重定位:就是将指令中无效的地址替换掉,分配已存在的正确的地址。
4)extern声明的变量在,o文件中符号表显示为*UND*(未知的变量)
运行过程:
1)创建虚拟空间到物理内存的映射,创建页目录和页表。
2)加载代码段和数据段。
3)将可执行文件的入口地址写到CPU的PC寄存器中去。
question:为什么.o文件不可以执行?因为在没有链接之前,是还没有为符号表中的符号分配虚拟地址的。没有办法映射到物理地址,自然也就没有办法运行。