一个简单的HELLO WORLD,整个编译过程中涉及到很多机制,这里是一片片海洋,从编译到链接,到装载入内存,这里的奥秘无穷无尽。
这是一本好书,不过目前只是草草读过,择自己现阶段的疑惑进行找答案,主要还是在静动态链接和库那里,做一起笔记,相信这本书以后还会读第二遍第三遍...
编译:
常用的编译器为GCC,其是一组编译工具的总称。包括:
C编译器:cc/cc1/cc1plus/gcc
C++编译器:c++/c++ plus,g++
源码预处理程序:cpp/cpp0
库文件:libgcc.a/libgcc_eh.a/libgcc_so…
编译的几个步骤:
一、预处理(pre-processing)--文件从.cpp到.i/.ii文件。主要处理源码文件中以“#”开始的预编译指令。如#inulude
#define….处理规则:
一、删掉所有的#define,并展开所有的宏定义。
二、处理所有的条件预编译命令。
三、递归处理#include指令,在用到的地方加载进去。
四、删掉所有的注释。
五:添加行号。
二、编译(compiling)—将源码编译成汇编生成.s文件。
编译就是将预处理完的文件进行一系列词法分析、语法分析、语义分析、优化生成汇编代码。而根据源文件为c/c++,gcc会调用不同的编译器,对应上面所提到的进行编译。其实gcc只是上面工具包的包装,它会根据不同参数去调用预编译程序cc1、汇编器as、链接器ld.
这也就是为什么我们可以用gcc命令可将编译整个过程拆分开来。
三、汇编(assembling)—将汇编码生成机器码.o文件【elf格式】
这个过程比较简单,只需根据汇编码对应的机器码进行变换即可。目标文件里有什么?
File header
.text section 代码段
.data section 数据段(已初始化全局变量、局部静态变量)
.bss section (未初始化全局变量、局部静态变量) 大小为0,在最终链接成功成可执行文件时再在Bss段分配空间。
.rel.text .rel.data 重定位表 记录需要重新定位的点
符号 【为链接留的接口】
链接时两个不同的目标是如何完成对接?当然要有暗号,这个暗号就是符号,当目标连接时,实际上是目标文件之间地址的引用,多数时候是对函数和变量地址的引用。称“定义与引用”
就像函数的声明与调用一样,不过这是在两个目标之间进行。每个目标文件中都会有一个对应符号表,每个符号对应一个符号值,也就是地址。
C++符号修饰 解决函数重载问题
在编译生成目标文件时,函数会被不同函数签名来表示,里面包括函数名、参数类型、所在的类、命名空间等。不同函数签名可将其分开来。
为何要将代码段与数据段分开?提高cache命中率、在动态分配时可共享数据段,减少内存
运行时库CRT的作用 :
C运行时库除了给我们提供必要的库函数调用(如memcpy、printf、malloc等)之外,它提供的另一个最重要的功能是为应用程序添加启动函 数。
C运行时库启动函数的主要功能为进行程序的初始化,对全局变量进行赋初值,加载用户程序的入口函数。
四、链接(linking) 链接包括静态与动态。
链接类似团块的连接,将各个相互联系着的模块完美地拼接在一起才会生成一个可执行文件。链接过程中一定要参与的对象是运行时库里面的目标文件,而又根据重定位点(两种链接不同点有很多,只是这个比较重要)不同分为静态链接和动态链接。
首先链接完成的工作有:地址和空间的分配,符号决议,重定位。
静态链接:在目标文件生成,但链接开始之前,其代码段和数据段的地址都为0x00000000(32位系统),当两个目标链接合并的时候,其.text section/.data section /.bss section要进行相似合并,虚拟地址分配建立映射关系,同时进行符号解析,地址重定位。什么是地址重定位?上面提到在目标文件中会一一对应有一个重定位表,也就是不同目标文件之间的相互引用的一些函数等地址,这些地址在链接后就会定下来,要引用的目标也会进行重新的调整。
静态链接的特点是在链接时进行重定位,而在动态链接中,是在装载时进行重定位。静态链接的产物是一个可执行文件,而动态链接的产物是一个个目标文件和共享对象(动态链接库),也就是一个个模块,这些模块在装载到内存中才会拼起来,在静态链接本就重定位的那些点,动态链接中将其标记起来,待到装载时再重定位。为什么动态链接要采用模块化的思想,很显然,有很多目标文件会共用一些库,采用动态链接时,在装载过程中,已存在的某些库就不用再重装入内存。而静态链接目标文件与依赖的文件已固化成一块,只能再一起加载进去,会造成内存浪费。图中lib.o只需装载一次。同时动态链接可增强程序的可扩展性和兼容性,因为动态链接就是在程序运行过程中动态地选择加载某个模块,而如果要对系统进行升级,直接对该模块进行覆盖即可,而静态链接就要整个可执行文件替换掉。
运行时库里面有很多常用的函数的源码cpp,同时还有每个函数对应生成的一个目标O文件,这个O文件被打包在一起形成libc.a叫静态库文件。如printf.o里面只有printf()。
在静态链接时,需要进行与目标文件进行链接,链接器会在lib.a(linux)/.lib(win)里面找到所需要的目标文件,其中还有一些用来初始化和启动的目标文件也同时被链接起来。
在动态链接时,库里面的各个O文件会被链接起来,生成共享对象(shared object).so(linux)/动态链接库(dynamic link library).dll(win)。然后再与主程序形成的目标文件进行动态链接。
Linux共享库系统路径
/lib 系统最关键最基础的共享库
/usr/lib 也为系统中的库,但非关键
/usr/local/lib 跟操作系统无关的第三方共享库
过程比较混乱,读不懂的部分请pass...