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元类的用法,在上一篇文章当中我 ...
随机推荐
- python - bilibili(四)抓包数据乱码
上一篇文章中不知道大家发现端倪木有,两张照片对比很明显发现第一张是信息很明显的,第二张是乱码的. 为什么会出现这种情况?细心的童鞋可能发现是我们发送给服务器的请求连接的数据不同: 第一张图的信息是{& ...
- SpringMvc多视图配置(jsp、velocity、freemarker) 在src目录views.properties配置
#welcome为modelAndView.setViewName(" welcome " ) ; 中的welcome .(class)固定写法 welcome.(class)=o ...
- java IO之 字符流 (字符流 = 字节流 + 编码表) 装饰器模式
字符流 计算机并不区分二进制文件与文本文件.所有的文件都是以二进制形式来存储的,因此, 从本质上说,所有的文件都是二进制文件.所以字符流是建立在字节流之上的,它能够提供字符 层次的编码和解码.列如,在 ...
- mongoDB 学习笔记纯干货(mongoose、增删改查、聚合、索引、连接、备份与恢复、监控等等)
最后更新时间:2017-07-13 11:10:49 原始文章链接:http://www.lovebxm.com/2017/07/13/mongodb_primer/ MongoDB - 简介 官网: ...
- Tkinter开发第一个桌面程序HelloWorld
在Python3中是tkinter,Python2中是Tkinter Tkinter是Python 官方承认的标准 GUI 方案(de-facto standard),因为是Python自带安装,决定 ...
- flume 1.7在windows下的安装与测试
一.安装 安装java,配置环境变量. 安装flume,下载地址,下载后直接解压即可. 二.运行 创建配置文件:在解压后的文件 apache-flume-1.7.0-bin\conf下创建一个exam ...
- Python面向对象编程(四)
1.多态 多态的概念虽然现在才说,但是我们一直在用.多态就是多种形态的意思,动物都猫,狗,猪等等,这些都是动物的多种形态. 反映在Python中,多态就意味着就算不知道变量所引用的对象类型是什么,也能 ...
- Miller-Rabin 素性测试
根据费马小定理,若p为素数,则必有a^(p-1) mod p=1 对和p互质的a成立. 根据二次探测定理:如果p是素数,且0<x<p,则方程x^2 mod p=1的解为1或p-1. 所以若 ...
- 回味Python2.7——笔记1
一.基本知识 1.一个值可以同时赋给几个变量: >>> x = y = z = 0 # Zero x, y and z >>> x 0 >>> y ...
- 【Mysql】复制表结构+数据(转)
1:复制表结构及数据到新表 select * into 目的数据库名.dbo.目的表名 from 原表名 select * into my0735home.dbo.infoMianTest from ...