被隐藏了的过程

   现如今在流行的集成开发环境下我们很少需要关注编译和链接的过程,而隐藏在程序运行期间的过程可不简单,即使使用命令行来编译一个源代码文件,简单的一句"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进阶—详解编译、链接的更多相关文章

  1. Jenkins企业应用进阶详解(一)

    Jenkins企业应用进阶详解(一) 链接:https://pan.baidu.com/s/1NZZbocZuNwtQS0eGkkglXQ 提取码:z7gj 复制这段内容后打开百度网盘手机App,操作 ...

  2. L011系统文件属性知识进阶详解小节

    L011系统文件属性知识进阶详解小节 这节课的内容相对来说较少,一上午加中午就听完了,现在总结一下,最后会有一个相关的面试题. 首先先附上一张图: 今天学习主要跟①和②有关,①为Inode 号 ②为文 ...

  3. Linux 链接详解----静态链接实例分析

    由Linux链接详解(1)中我们简单的分析了静态库的引用解析和重定位的内容, 下面我们结合实例来看一下静态链接重定位过程. /* * a.c */ ; void add(int c); int mai ...

  4. shell脚本进阶 详解及其实例(一)

    v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VM ...

  5. 【FPGA篇章六】FPGA编译向导:详解编译预处理功能

    欢迎大家关注我的微信公众账号,支持程序媛写出更多优秀的文章 Verilog HDL语言和C语言一样也提供了编译预处理功能. Verilog HDL允许在程序中使用特殊的编译预处理语句. 在编译时,通常 ...

  6. Linux ll查看文件属性详解-软硬链接详解

    Linux文件属性及类型 [root@localhost ~]# ll anaconda-ks.cfg 文件类型 权限 硬连接数 文件的大小 文件的创建,修改时间 - rw-------. 1 roo ...

  7. T-SQL查询进阶--详解公用表表达式(CTE)

    简介 对于SELECT查询语句来说,通常情况下,为了使T-SQL代码更加简洁和可读,在一个查询中引用另外的结果集都是通过视图而不是子查询来进行分解的. 但是,视图是作为系统对象存在数据库中,那对于结果 ...

  8. pm2 start命令进阶详解

    在node的世界里面,并不存在nginx或者apache,甚至tomcat这种东东.一个node,本身就用几行代码,就可以启动个server进程,监听个端口,为大家提供web服务.这和传统的网站代码的 ...

  9. Python进阶——详解元类,metaclass的原理和用法

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是Python专题第18篇文章,我们来继续聊聊Python当中的元类. 在上上篇文章当中我们介绍了type元类的用法,在上一篇文章当中我 ...

随机推荐

  1. hdu2415(树上背包)

    这道题好像没什么人写题解,于是写了一发 题意:有个坏蛋想要参加竞选,需要得到m个人的支持,买通第i个人(1<=i<=n)需要一个cost[i],同时这些人又有上下属关系,只要买通了领导,他 ...

  2. js中嵌入jsp(html)代码的双引号转换问题--事件没反应

    下面是一段今天遇到问题的代码,select中写了onchange事件 ,在没有加转义的情况下,F12解析的代码是错乱的,双引号与内容中写的不一致,还会有空格出现,经过一段时间的摸索,发现在出错的地方加 ...

  3. 终于等到你!MobileTest免费公测,华为带你走出安卓适配大坑

    一.安卓适配之痛真的无解吗? Android平台的诞生对智能手机的普及功不可没,但设备繁多.品牌众多.版本各异,芯片.摄像头.分辨率不统一等等,这些都逐渐成为Android系统发展的障碍,碎片化严重不 ...

  4. java.util.Arrays类

    前言:java.util.Arrays类的技术文档请查看Oracle官网 1.Arrays类常见方法: 本文参考资料:百度文库:Oracle官网:第三方中文技术文档

  5. 记录Centos一些坑

    首先说一下写这篇博客的初衷. 最近去客户现场出差,搭建一套服务端的自动构建环境. 准备支持的环境有CentOS 7.5.java8.Tomcat 8.maven3.3.9.TBA 2.1.9.4 等等 ...

  6. 了解Java并学会创建Java项目(一个菜鸟的成长历程)

    计算机语言分类:了解 1)低级语言:更接近于计算机的语言 1.1)机器语言:由0和1组成的 1.2)汇编语言:有一些助记符号2)高级语言:更接近于人的语言 2.1)面向过程的:C... 2.2)面向对 ...

  7. 前端javascript中字符串的总结

    1.截取方法 截取字符串的abcdefg中的efg. 注意:str.length从1的开始数 var str="abcdefg"; (1).slice() : console.lo ...

  8. 解决删除元素动画的bug

    效果说明 首先说明一下我需要做到的效果 其实很简单---点击删除按钮的时候,加入删除动画 删除动画是这样的,高度和宽度都会均匀的变小,内部的元素需要被隐藏(因为会有文字挤在一起):直到变为0结束,时长 ...

  9. 如何快速查看github代码库中第一次commit的记录

    发现一个别人推荐的代码库用来学习源码, star星还不少,别人推荐从第一次commit开始阅读,于是试着去找commits的第一次 问题来了,这个代码库commits7855次,点击进入commits ...

  10. python教程6-3:排序

    (a).输入一串数字.并从大到小排列. (b).跟a一样,不过要用字典序从大到小排列. python35 PaiXu_6_3.py PaiXu_6_3.py #coding=utf-8 import ...