编译和链接
前阵子看了一下《程序员的自我修养:链接、装载与库》,觉得还是有一些收获,做了一些笔记,记录一下。
编译和链接
首先是一个hello world,这是一个最基础的程序,如下:
1 |
|
通过gcc编译:
1 | gcc hello.c |
就可以输出字符串了。这其实是封装好的过程,实际的过程包括了:
- 预处理
- 编译
- 汇编
- 链接
具体过程如下:
预处理
首先是源代码文件hello.c和相关的头文件,如stdio.h被预编译器cpp编译成一个.i文件。对于C++预编译的扩展名是.ii。第一步的过程如下:
1 | gcc -E hello.c -o hello.i |
打开hello.i,其中有处理后的C代码。主要的处理如下:
- 将所有的”#define”删除,展开宏定义
- 处理所有的条件编译指令,比如”#if”,”#ifdef”,”#elif”,”#else”,”#endif”。
- 处理#include文件,将被包含的文件插入到该预编译指令的位置。这里是递归进行
- 删除所有注释
- 添加行号和文件名标识,以便于编译器产生调试用的行号信息等
- 保留所有的#pragma指令,编译器需要使用它们
编译
在这里就使用编译原理学过的词法分析,语法分析,语义分析,然后优化后生成对应的汇编代码文件
现代版本的gcc把预编译和编译用ccl来完成,也可以用
1 | gcc -S hello.c -o hello.s |
汇编
汇编器将汇编代码转化为二进制指令,用as来完成
1 | as hello.s -o hello.o |
或者
1 | gcc -c hello.s -o hello.o |
也可以用gcc从源代码开始:
1 | gcc -c hello.c -o hello.o |
链接
将汇编生成的目标文件用ld链接起来,生成可执行文件。
静态链接是一种模块的拼装。
- 地址和空间分配
- 符号决议
- 重定位