-------------前言
浑浑噩噩就看完了一遍《高级c/c++编译技术》,我知道看完一遍是不行,而且光是看也是不行的,先写下这篇博文也权当是记录下我的一些猜想,当然是未经过验证的,经过验证就不是猜想了。最终,在下有什么说得不对的,请各位大侠指正,不断学习不断进步!
-------------正文
先说一下这本书。这本书是由Milan Stevanovic大佬写的,卢誉声所译。结构内容是硬件基础,程序的生命周期,生命周期中的各个阶段的介绍,各类问题的解决。
第一章讲解的是他的硬件支持,因为最终编译是要编译成机器能够读懂的二进制语言,所以首先我们先要知道我们的目的是什么,高级语言c/c++----------》某种工具(先把他当成一个黑箱)-------------》二进制文件。那么,机器能够读懂的二进制语言是需要到专用的芯片的指令,更重要的是指令的地址怎么得到,怎么做才能得到我们的二进制文件,怎么做才能解决我们问题。这就是我大概能读懂的意思,我还没看过操作系统,一些更深的东西还没看懂。
总结起来就是,最终我们要控制的是我们的I/O设备,主存释放字节流,作为与IO进行数据交换的直接港口,主存被要求速度必须快,但是受成本问题,往往越大越贵,所以有一种缓存机制,一个折中的方法。缓存往往有多级,接近IO的越快,接近cpu的慢,这种分级制度在某种程度上起到了缓冲的作用,但是不可避免的,当IO数据量很大的时候,主存往往会请求硬盘帮忙,这就使虚拟内存的机制,这时就会显得很卡。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。
怎么做到让它看起来是连续的呢?
实际上物理地址是不连续的,而是给物理地址的编号是连续的,在学数字电路和微机原理的时候,会教到一个就是给ram分配地址,按照事先约定好的规则,可以使它的地址号读取是连续的。比如说奇偶地址位的读取来满足cpu的设置,intel8086的cpu有一个管脚说明是奇偶读取地址,为了满足的它的整体的一个架构,ram和译码器什么的组合起来让cpu看上去真的是在读奇偶地址的。再详细的只能去再查课本了。
程序的生命周期有:
编译,链接,两个阶段,经过这两个阶段:
c/c++--------->编译---------->汇编程序---------->链接--------------->二进制文件
二进制文件------------->装载----------------->赋予绝对地址(可寻址),执行
ok,我们一步步来介绍。
编译:
1.执行单元:编译器
2.输入:编译单元(通常为包含源代码的文本)
3.输出:一系列的二进制目标文件的集合
注意:此时的输出虽然是二进制文件,但是是每个源文件对应的目标文件,也就是他们之间的联系还没有连接起来。
ok,要成以上的输入变成输出,编译器到底做了什么事情呢?
1.预处理阶段
输入:c/c++
输出:c/c++
使用一个特殊的文本处理程序,将宏进行替换。将include关键字标识的含有特定文件包含到源码文件中,将define语句指定的值转换成常量,将ifndef或ifdef、eleif和endif做相应的处理。
2.语言分析阶段
输入:c/c++
输出:c/c++
最终得到一个精简的、符合语法、语义的代码。有以下的几个方面的过程:
1.词法分析:将源代码分割成不可分割的单词
2.语法分析:将提出的单词连成序列,并根据编程语言规则进行检查,验证其顺序是否合理。
3.语义分析:目的是发现符合语法规定的语句是否具有实际意义。
3.汇编过程
输入:c/c++
输出:汇编代码
转换成特定cpu指令集的语言集合。经过1、2这两个步骤,可以保证现在的c/c++代码是精简有意义的存在了。那么就可以把它转换成汇编代码了。以gcc编译器为例:
源代码------------->gcc---------------->ASCII编码的文本文件
x86处理器体系结构的支持两种指令格式:AT&T intel 格式
4.优化阶段
输入:汇编代码
输出:汇编代码
最初版本的汇编代码--------------------->优化-------------------------->最终版汇编代码
优化的原则:
1.将寄存器使用率最小化
2.通过分析能够预测出实际上不需要执行的部分代码
5.代码生成阶段
输入:汇编代码
输出:多个二进制文件集合
每一个目标文件对应一个编译单元,汇编指令转成成对应的机器指令(操作码)的二进制值。
ok,这个编译就完成了,再Linux上面,我们可以通过命令
gcc -S -o
gcc -S -masm=intel hello.c -o hello.s
这就是汇编程序了,但是我汇编还没看过,不怎么懂,所以就不做分析了。知道是可以得出汇编程序的。
gcc -c hello.c -o hello.o
就得到了hello.o也即二进制文件,虽然你看着只有一个,但是别忘了你在刚开始学习得时候就不明白的为什么要include一个什么鬼东西呢,那个鬼东西在哪呢?那个东西就是共享库,之后会介绍到,现在先不谈。
所以,咱们通过这个命令就可以得到了二进制目标文件了,但是我们要查看的话需要十六进制的文件查看器,我没有,直接用vim是一堆乱码就不截图了。
至此,编译过程结束。往后请看下一节。