程序员的自我修养学习笔记——第二章

从源文件到可以行文件的过程:

 

预处理——编译——汇编——链接

 

第一步

预编译:

$gcc  -E hello.c -o hello.i

或者

$cpp hello.c > hello.i 

注:‘-E’选项表示只进行预编译;cpp是预编译器

  

预编译主要处理一‘#’开头的预编译指令: 

将所有的"#define"删除,并且展开所有的宏定义

处理所有条件预编译指令

处理"#include",将包含的文件插入到该预编译指令的位置。注意,这个过程是递归进行

删除所有注释

添加行号和文件名标识,以便于调试和编译产生的错误和警告

保留所有"#pragma"指令,编译器需要使用它们

 

编译: 

$gcc  -S  hello.i -o hello.s 

也可以将编译和预编译合并,通过一个gcc提供的程序ccl来完成: 

$/usr/lib/gcc/usr/lib/gcc/i686-pc-cygwin/ccl   hello.c 

或者:

$gcc  -S  hello.c -o hello.s

实际上gcc这个命令只是一些列后台程序的包装,它会根据不同的参数要求去调用预编译程序ccl、汇编器as、连接器ld。

汇编:是将汇编代码转换为机器码的过程

这样来完成汇编: 

$as  hello.s  -o hello.o 

或者:

$gcc  -c  hello.s  -o  hello.o 

或者:从.c文件开始

$gcc  -c  hello.c  -o  hello.o

链接:将.o文件变为可执行文件的过程(这是一个复杂的过程)

需要经过下面的一些命令来完成:

ld  -static  crt1.o  crti.o  crtbeginT.o  hello.o  -start-group -lgcc   -lgcc_eh

 -lc-end-group  crtend.o  crtn.o

注:到后面的时候记录一下各个参数的作用,然后在这里补充 

编译器都做了什么:

编译过程一般可以分为6步:扫描、语法分析、语义分析、源代码优化、代码生成和目标代码优化。

 

词法分析: 

运用有限状态机(Finite State Machine)可以轻松的将源代码的字符序列分割成一系列的记号。

此法分析产生的记号一般有一下几类:关键字、标识符、字面量(包含数字、字符串等)和特殊符号(如加号、等号)

语法分析: 

语法分析器(Grammar Parser)将对由扫描器产生的记号进行语法分析,从而产生语法树。

由语法分析器生成的语法树就是以表达式为节点的树。 

语义分析:  

    编译器所能分析的语义是静态语义,所谓静态语义是指在编译期间可以确定的语义,与之相对应的动态语义,就是在运行期才能确定的语义。 

    函数访问必须知道目标函数的地址,变量访问也必须知道目标变量的地址,所以这两种方式都可以归结为一种方式,那就是模块间符号的引用。 

    人们把每个源代码模块独立地编译,然后按照需要将它们组装起来,这个组装模块的过程就是“链接”

    链接的主要内容就是把各个模块之间相互引用的部分处理好,使得各个模块之间能够正确衔接。

    链接过程主要包括地址和空间分配、符号决议和重定位。

     重定位发生在链接阶段,如果一个模块需要使用另一个模块的变量或函数,编译的时候先给这个变量或函数一个特殊的地址,链接的时候再来确定实际地址。这个  地址修正的过程也叫做重定位,每个要被修正地方叫一个重定位入口。

make it simple, make it happen
原文地址:https://www.cnblogs.com/zhuyp1015/p/2475770.html