编译原理
1
2
3
4
5
6
7
8
9
|
编译过程大致可以分为五个步骤
1.
词法分析:读入源程序字符流,输出有意义的词素;
2.
语法分析:根据各个词法单元的第一个分量来创建树形的中间表达式,
通常是语法树;
3.
语义分析:使用语法树和符号表中的信息,检测源程序是否满足语言
定义的语义约束,同时收集类型信息,用于代码生成,类型检查和类型转换;
4.
中间代码生成和优化:根据语义分析输出,生成机器语言的中间表示,
如三地址码。然后对生成的中间代码进行分析和优化;
5.
代码生成和优化:把中间表示形式映射到目标机器语言;
|
gcc编译过程
编译时添加“-save-temps”(保存编译过程中生成的中间文件) 和 “--verbose”(查看gcc编译的详细工作流程),下面是输出。
可以看到gcc编译主要包括四个阶段:预处理,编译,汇编和链接。
1.其中ccl是编译器对应一二阶段,将hello.c编译成hello.s;
2.as是汇编器,对应第三阶段,将hello.c汇编为hello.o;
3.collect2是链接器,是对ld命令的封装,用于将c语言运行时库(CRT)中的目标文件(crtl.o,crti.o...)以及动态链接库链接(libgcc.so,libgcc_s.so,libc.so)到可执行hello;
预处理阶段
1
|
主要处理预处理指令,替换
'#'
后面的内容,直接插入到程序文本中,得到另一个c程序,扩展名为“.i”;
|
编译阶段
1
|
在命令中添加“
-
S”选项,操作对象可为“.c”也可为“.i”。需要注意的时gcc默认使用AT&T格式,而我们熟悉的intel格式需要加“
-
masm
=
intel”选项, 选项“
-
fno
-
asynchronous
-
unwind
-
tables”用于生成没有cfi宏的汇编指令;
|
注意printf()函数被puts()替换是因为printf单一参数时gcc做的优化策略;
汇编阶段
1
|
可使用选项“
-
c”来处理“.s”或“.c”文件得到“.o”目标文件,此时hello.o是可重定位文件,可用objdump命令来查看其内容;
|
由于未进行链接,对象文件中的虚拟地址无法确定,所以我们可以看到“hello, world”的地址设置为“0x0000”
链接阶段
1
|
链接可分为静态链接和动态链接两种。gcc默认使用动态链接,添加“
-
static”选项可指定使用静态链接。
|
这一阶段将目标文件及其依赖库进行链接,生成可执行文件。主要包括地址和空间分配,符号绑定和重定位等操作。
执行“gcc hello.o -o hello -static”后你将得到静态链接的可执行文件,它包含了大量库文件。且对象文件中无法确定的符号地址已被替换为实际的符号地址。
补充
1.可自行搜索动态链接和静态链接的基础知识;
2.《二进制分析实战》附录有x86-64汇编的快速入门,建议先看看8086的汇编入个门。
更多【(pwn零基础入门到进阶)第一章 二进制文件 & 1 编译原理】相关视频教程:www.yxfzedu.com