程序的翻译环境
在ANSI C的实现中,存在两个不同的环境:翻译环境和执行环境。
翻译环境中源代码被转换为可执行的机器指令,执行环境用于实际执行代码。
翻译环境:
链接库:调用某一个函数时,会把和该函数相关的几个库一起链接进去。
组成一个程序的每个源文件通过编译过程分别转换成目标代码,每个目标文件由链接器捆绑在一起,形成一个单一而完整的可执行程序,链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库,将其需要的函数也链接到程序中。
编译阶段
在CentOS上写如下test.c程序:
(1)预处理阶段:
执行gcc test.c -E>test.i
执行vim test.i查看.i文件,滚动到底部可以看到红色框内的代码,前面都是预处理时替换的内容,MAX(a,b)也被替换为((100)>(200)?(100):(200)),且注释不见了。
以蓝色框内flockfile、ftrylockfile、funlockfile函数为例查看预处理时是如何替换库函数的:查看/usr/include/下的头文件
vim 查看stdio.h文件,滚动到底部,可以看到flockfile、ftrylockfile、funlockfile函数,预处理使用stdio.h的内容将#include<stdio.h>替换了
这说明执行gcc test.c -E>test.i做了3件事:1.完成头文件的包含,2#define定义的宏的替换,3.删除注释。
(2)编译阶段
执行gcc test.i -S
vim test.s,可以看到里面都是汇编代码
编译阶段主要把C语言代码转化成汇编代码,包括语法分析、词法分析、语义分析、符号汇总。
(3)汇编阶段
执行gcc test.s -c,生成test.o文件
test.o文件时elf格式的,使用readelf工具查看,执行readelf test.o -s查看test.o文件,生成的符号名有g_val、Add、main、printf分别对应源文件的全局变量和函数。
汇编阶段把汇编代码转换成机器指令(二进制指令)生成目标文件,形成符号表。
链接阶段
将test.c中Add函数的执行放在add.c文件中:
test.c
add.c
编译成目标文件,查看目标文件:
test.o
add.o
可以看到test.o和add.o中的符号表都包含Add,但是test.o中的Add函数没有意义,只是声明而已。在链接阶段会合并段表,并进行符号表的合并和重定位。
编译链接阶段的执行过程: