C进阶—详解编译、链接
被隐藏了的过程
现如今在流行的集成开发环境下我们很少需要关注编译和链接的过程,而隐藏在程序运行期间的过程可不简单,即使使用命令行来编译一个源代码文件,简单的一句"gcc hello.c"命令就包含了非常复杂的过程。
1 #include<stdio.h>
3 int main()
4 {
5 printf("Hello word\n");
6 return 0;
7 }
在Linux系统下使用gcc编译程序时只须简单的命令:
$gcc hello.c
$/a.out
Hello word
不管哪种编辑器,以上过程可分为4个步骤,分别是预编译(Prepressing)、编译(Compilation)、汇编(Assembly)、链接(Linking)。
GCC 编译过程分解
预编译
首先是将源代码文件hello.h和相关的头文件,如stdio.h等被编译器Cpp预编译成一个.i文件。主要处理那些源文件中以“#”开始的预编译指令,如“#include"、”#define“等,主要规则如下:
将所有的”#define“删除,并且展开所有的宏定义。
处理所有条件预编译指令,比如”#if”、”#ifdef“、”#elif“等。
处理”#include“预编译命令,将被包含的文件插入到该预编译指令的位置。注意,这个过程是递归进行的,也就是说被包含的文件可能还包含其他文件。
删除所有的注释”//“和”/**/“。
添加行号和文件名标识,比如#2”hello.c“2,以便于编译器产生调试用时的行号信息及用于编译时产生编译错误或警告时能显示行号。
保留所有的#pragma编译器指令,因为预编译器需要用他们。
编译
编译过程就是把预处理完的文件进行一系列词法分析、语法分析、语义分析、生成汇编文件,这个过程是是整个程序构建的核心部分,也是最复杂的部分之一。gcc将预编译和编译合并成一个步骤,使用如下命令:
$gcc -s hello.c -o hello.s
可得到会变输出文件 hello.s 。实际上gcc这个命令只是这些后台程序的包装,它会根据不同的参数要求去调用预编译编译程序cc1、汇编器as、链接器ld。
编译器职责
词法分析 经过预编译的源代码程序被输入到扫描器(Scanner),扫描器对其进行简单的词法分析,运用一种类似于有限状态机的算法将源代码的字符列分割成一系列的记号。如:关键字、标识符、字面量(包含数字、字符串等)和特殊符号(如加号、等号)。在标别记号的同时扫描器也完成了其他如将标识符存放到符号表,将数字、字符串常量存放到文件表等的工作,以备后面的步骤使用。(lex程序可实现词法扫描,按照一定的词法规则完成标别记号等功能,所以无需为每个编译器开发一个独立此法扫描器,而是根据需要改变语法规则即可。)
语法分析 语法分析器采用上下文无关语法的分析手段对扫描器产生的记号(Token)进行语法分析,从而生成语法树,即一表达式为节点的树。同时很多运算符的含义和优先级也被确定下来。编译器也会报告出语法分析阶段的错误。(如词法分析有像lex一样语法分析有现成工具ycc,它可根据语法规则对输入的记号序列构建出一颗语法树。对不同的编程语言只须改变语法规则即可。)
语义分析 语义分析由语义分析器完成,它所能分析的语义是静态语义,即编译期间可以确定的语义,运行期间才能确定的语义是指动态语义。静态语义通常包括生命和类型匹配,类型转换,如浮点型到整型转换。经过语义分析以后整个语法树都被标识了类型,如果有些类型需要做隐式转换,语义分析程序会在语法树中插入相应的转换节点。语义分析器对符号表里的符号类型也做了更新。语法分析仅仅完成对表达式语法层面的分析, 该语句是否有意义不进行检测。
符号汇总 源码优化器会在源代码级别进行优化,它往往将整个语法树转换成中间代码,它是语法树的顺序表示,已非常接近目标代码。中间代码有多种类型,常见的有三地址码,P-代码。中间代码使得编译器可分成前端和后端,前段即产生中间代码,后端将中间代码转换成目标机器代码。编辑器主要包括代码生成器和目标代码生成器。代码生成器将中间代码转换成目标机器代码。目标代码优化器再对其进行优化,如选择合适的寻址方式、使用位移来代替乘法运算、删除多余指令等。
汇编
汇编器是将汇编代码变成机器可以执行的指令,每一条汇编指令几乎都对应一条机器指令,根据其对照表一一翻译即可。目标文件中还包括链接是所需要的一些调试信息: 比如符号表、 调试信息、 字符串等。
链接
人们把每个源代码模块独立的进行编译,然后按照需要将它们组装起来,这个组装的过程就是链接(Linking)。
未解决的符号表: 列出本单元里有引用但是不在本单元定义的符号以及地址。导出符号表: 本单元中定义的一些符号(全局、静态变量和函数) 和地址的映射表。地址重定向表: 提供了本编译单元所有对自身地址的引 用记录。连接器的工作顺序:当连接器链接的时候, 首先决定各个目标文件在最终可执行文件里的位置。然后访问所有目标文件的地址重定义表, 对其中记录的地址进行重定向 (加上一个偏移量, 即该编译单元在可执行文件上的起始地址) 。然后遍历所有目标文件的未解决符号表, 并且在所有的导出符号表里查找匹配的符号, 并在未解决符号表中所记录的位置上填写实际地址。最后把所有的目标文件的内容写在各自的位置上,和库(Library)一起链接,形成最终的可执行文件。
总结:
C进阶—详解编译、链接的更多相关文章
- Jenkins企业应用进阶详解(一)
Jenkins企业应用进阶详解(一) 链接:https://pan.baidu.com/s/1NZZbocZuNwtQS0eGkkglXQ 提取码:z7gj 复制这段内容后打开百度网盘手机App,操作 ...
- L011系统文件属性知识进阶详解小节
L011系统文件属性知识进阶详解小节 这节课的内容相对来说较少,一上午加中午就听完了,现在总结一下,最后会有一个相关的面试题. 首先先附上一张图: 今天学习主要跟①和②有关,①为Inode 号 ②为文 ...
- Linux 链接详解----静态链接实例分析
由Linux链接详解(1)中我们简单的分析了静态库的引用解析和重定位的内容, 下面我们结合实例来看一下静态链接重定位过程. /* * a.c */ ; void add(int c); int mai ...
- shell脚本进阶 详解及其实例(一)
v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VM ...
- 【FPGA篇章六】FPGA编译向导:详解编译预处理功能
欢迎大家关注我的微信公众账号,支持程序媛写出更多优秀的文章 Verilog HDL语言和C语言一样也提供了编译预处理功能. Verilog HDL允许在程序中使用特殊的编译预处理语句. 在编译时,通常 ...
- Linux ll查看文件属性详解-软硬链接详解
Linux文件属性及类型 [root@localhost ~]# ll anaconda-ks.cfg 文件类型 权限 硬连接数 文件的大小 文件的创建,修改时间 - rw-------. 1 roo ...
- T-SQL查询进阶--详解公用表表达式(CTE)
简介 对于SELECT查询语句来说,通常情况下,为了使T-SQL代码更加简洁和可读,在一个查询中引用另外的结果集都是通过视图而不是子查询来进行分解的. 但是,视图是作为系统对象存在数据库中,那对于结果 ...
- pm2 start命令进阶详解
在node的世界里面,并不存在nginx或者apache,甚至tomcat这种东东.一个node,本身就用几行代码,就可以启动个server进程,监听个端口,为大家提供web服务.这和传统的网站代码的 ...
- Python进阶——详解元类,metaclass的原理和用法
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是Python专题第18篇文章,我们来继续聊聊Python当中的元类. 在上上篇文章当中我们介绍了type元类的用法,在上一篇文章当中我 ...
随机推荐
- Linux下安装openvpn
工作上常常要通过vpn访问内网环境,最近一直在linux上搞东西,为了方便起见在linux上也安装了openvpn. 本次安装的openvpn不是把它当做服务端,而仅仅是以客户端来使用,所以没有那些服 ...
- Chrome浏览器扩展开发系列之十:桌面通知Notification
Desktop Notification也称为Web Notification,是在Web页面之外,以弹出桌面对话框的形式通知用户发生了某事件.Web Notification于2015.9.10成为 ...
- voa 2015.4.29
Nepal has declared three days of mourning for the victims of Saturday's 7.8 magnitude earthquake tha ...
- 利用workbench将excel数据导入到MySQL中
数据导入的方式(csv,txt之类) 在MySQL中,数据导入的方式有两种方式 通过第三方客户端导入(workbench) 通过mysql client 方式导入 通过mysql clinet的导入方 ...
- ThinkPhp框架:分页查询和补充框架知识
上一篇的随笔写的是基本操作,现在可以做一些高级操作,例如有条件的查询数据,有分页的条件查询数据 一.一个条件的查询数据 查询数据自然是先要显示出数据,然后根据条件进行查询数据 (1)显示出表的数据 这 ...
- PHP树结构,实现无限分级
一.从数据库查出来的数据需要id.parentid.level. id唯一识别栏目,parentid为该栏目所属父类id,level标示该栏目是几级栏目.以下代码就可以实现一个简单的树结构. publ ...
- Ajax的方法和使用代码
//1.创建Ajax对象,已经封装好的函数: function createXHR(){ if (typeof XMLHttpRequest != "undefined"){ re ...
- ES6对象扩展
前面的话 随着JS应用复杂度的不断增加,开发者在程序中使用对象的数量也在持续增长,因此对象使用效率的提升就变得至关重要.ES6通过多种方式来加强对象的使用,通过简单的语法扩展,提供更多操作对象及与对象 ...
- 【PHP】 安装参数
1. 配置参数 './configure' '--prefix=/usr/local/php5.2' '--with-apxs2=/usr/sbin/apxs' '--with-mysql=/usr/ ...
- yii2 获取从前台传过来的post数据
第一次使用yii写接口的时候,直接用了$_POST获取post数据,发现会报400错误,根本无法获取到post数据,用$_GET却能获取get数据. 纠结了很久,然后查资料,发现原来yii中默认的开启 ...