一个程序从源代码到可执行程序的过程

#一个源程序到一个可执行程序的过程:

#预编译、编译、汇编、链接。 

其中,编译是主要部分,其中又分为六个部分:词法分析、语法分析、语义分析、中间代码生成、目标代码生成和优化。 

链接中,分为静态链接和动态链接,本文主要是静态链接。

##一、预编译:主要处理源代码文件中的以“#”开头的预编译指令。处理规则见下 

1.删除所有的#define,展开所有的宏定义。 

2.处理所有的条件预编译指令,如“#if”、“#endif”、“#ifdef”、“#elif”和“#else”。 

3.处理“#include”预编译指令,将文件内容替换到它的位置,这个过程是递归进行的,文件中包含其他文件。 

4.删除所有的注释,“//”和“/**/”。 

5.保留所有的#pragma 编译器指令,编译器需要用到他们,如:#pragma once 是为了防止有文件被重复引用。 

6.添加行号和文件标识,便于编译时编译器产生调试用的行号信息,和编译时产生编译错误或警告是能够显示行号。

C语言的宏替换和文件包含的工作,不归入编译器的范围,而是交给独立的预处理器。 

C语言中源代码文件的文件扩展名为.c,头文件的文件扩展名为.h,经预编译之后,生成xxx.i文件。 

在C++,源代码文件的扩展名是.cpp或.cxx,头文件的文件扩展名为.hpp,经预编译之后,生成xxx.ii文件。

##二、编译:把预编译之后生成的xxx.i或xxx.ii文件,进行一系列词法分析、语法分析、语义分析及优化后,生成相应的汇编代码文件。

(结合程序来说明编译的几个步骤) 

有C语言的源代码如下: 

arr[3] = (a+4)*(3+8);

1.词法分析:利用类似于“有限状态机”的算法,将源代码程序输入到扫描机中,将其中的字符序列分割成一系列的记号。 

以上的一行C语言程序,一共有16个空字符,经扫描机扫描之后,产生了16个记号。lex可以实现词法分析。见下表:

![屏幕快照 2018-11-01 下午7.39.38.png](https://upload-images.jianshu.io/upload_images/2734090-03f0dcab14bdfe14.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

见上图: 

词法分析产生的记号分类有:关键字、标识符、字面量(数字、字符串)、特殊符号(加号、等号等)

2.语法分析:语法分析器对由扫描器产生的记号,进行语法分析,产生语法树。由语法分析器输出的语法树是一种以表达式为节点的树。上述的代码就是 

各种表达式的组合:赋值表达式、加法表达式、乘法表达式、数组表达式和括号表达式组成的复杂表达式。yacc可以实现语法分析,根据用户给定的规则(不同的编程语言对应不同的语法规则)对记号表进行解析。

![屏幕快照 2018-11-01 下午7.44.34.png](https://upload-images.jianshu.io/upload_images/2734090-664bd1144d7d75f0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

见上图: 

整个语句被看作是一个“赋值表达式”,“=”左边是一个“数组表达式”,右边是一个“乘法表达式”。数组表达式又由两个符号表达式组成,符号表达式就是最小的表达式,之后同理。

在语法分析的同时,就把运算符的优先级确定了下来,如果出现表达式不合法,——各种括号不匹配、表达式中缺少操作,编译器就会报错。

3.语义分析:语法分析器只是完成了对表达式语法层面的分析,语义分析器则对表达式是否有意义进行判断,其分析的语义是静态语义——在编译期能分期的语义,相对应的动态语义是在运行期才能确定的语义。 

其中,静态语义通常包括:声明和类型的匹配,类型的转换,那么语义分析就会对这些方面进行检查,例如将一个int型赋值给int*型时,语义分析程序会发现这个类型不匹配,编译器就会报错。

经过语义分析阶段之后,所有的符号都被标识了类型(如果有些类型需要做隐式转化,语义分析程序会在语法树中插入相应的转换节点),见下图:

![屏幕快照 2018-11-01 下午7.45.05.png](https://upload-images.jianshu.io/upload_images/2734090-437cdefae8f1141c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

这个语句中的类型都是int型,无须做转换。

4.优化:*源代码级别的一个优化过程*,例如该语句中的(3+8)的值可以在编译期确定,源代码优化器会将整个语法树转换成中间代码——语法树的顺序表示,十分接近目标代码。 

中间代码有很多种类型,最常见的是“三地址码”和“P-代码”,其中三地址码的基本形式为:x = y op z,表示将变量y和z进行op操作后,赋值给x,op操作可以是加减乘除等。 

经优化之后的语法树为:

![屏幕快照 2018-11-01 下午7.45.27.png](https://upload-images.jianshu.io/upload_images/2734090-e65045185948ef0d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

该语句的三地址码: 

t1 = 3 + 8; 

t2 = a + 4; 

t3 = t2 * t1; 

arr[3] = t3;

t1由数字11代替,省去t3,经优化或的三地址码为: 

t2 = a +4; 

t2 = t2 + 11; 

arr[3] = t2;

另一个关于中间代码的要点:中间代码使得编译器可以被分成前端和后端,编译器前端负责产生与机器无关的中间代码,编译器后端将中间代码转换为机器代码。 

源代码优化去产生中间代码标志着下面的过程都属于编译器后端,后端主要包括:代码生成器和目标代码优化器。

5.目标代码生成:由代码生成器将中间代码转换成目标机器代码,生成一系列的代码序列——汇编语言表示。

6.目标代码优化:目标代码优化器对上述的目标机器代码进行优化:寻找合适的寻址方式、使用位移来替代乘法运算、删除多余的指令等。

上述的六个步骤完毕之后,编译过程也就告一段落了。最终产生了由汇编语言编写的目标代码。

gcc把预编译和编译两个步骤合并成一个步骤。对于C语言的代码,是用“cc1”这个程序来完成这两步,对于C++代码,对应的程序为“cc1plus”。gcc这个命令只是后台程序的包装,根据不同的参数去调用:预编译编译程序——cc1,汇编器——as,连接器——ld。

C语言的代码,经编译后产生的文件名为xxx.s。

##三、汇编:将汇编代码转变成机器可以执行的指令(机器码文件)。 

汇编器的汇编过程相对于编译器来说更简单,没有复杂的语法,也没有语义,更不需要做指令优化,只是根据汇编指令和机器指令的对照表一一翻译过来,汇编过程有汇编器as完成。

经汇编之后,产生目标文件(与可执行文件格式几乎一样)xxx.o(Windows下)、xxx.obj(Linux下)。

但是,经过预编译、编译、汇编之后,生成机器可以执行的目标文件之后,还有一个问题——变量a和数组arr的地址还没有确定。这就需要链接器来搞定啦~

##四、链接: 

1、历史过程:曾经,程序猿门在编程时,使用纸带作为最原始的存储设备,每当程序需要修改时,都要重新扎一条纸带,扎孔的表示1,不扎的是0,一串串1和0就组成了各种各样的指令——跳转等等…. 

每一次的修改都非常痛苦,所以先知们就发明了汇编语言,这种编程语言方便之处在于符号的引用,表示跳转指令不再需要记住一串串0和1,终于可以使用符号——foo来表示这个动作了! 

随着汇编语言的普及,程序的代码量也就开始快速膨胀了,汇编语言说它也撑不住了….不过还好,高级编程语言Fortran、C、C++等一个接一个地问世,语言越来越方便了,追求perfect的人们就想:代码咋写更好呢?可不可以把代码按照功能的不同,分成不同的部分,便于日后的修改和重复使用呢? 

有了这个启发,程序猿们越来越得心应手,他们开始把代码按照功能和性质划分,分别形成不同的功能模块,不同的模块之间又按照各种结构来组织。 

发展到如今,软件的规模越来越大,代码动辄数百万行代码,放在一个模块那是万万不行的,维护起来会非常麻烦,所有现在的大型软件往往拥有成千上万的模块, 

模块之间相互独立又相互依赖。 

新的问题来了,一个程序被分割成这么多模块,最后要怎么把这些模块组合形成一个单一的程序? 

答案就是:模块之间,符号的引用! 

这就像是一张画有大树的拼图,叶子、枝干、根系都零散的分布在那些拼图碎片上,想要看到完整的大树,我们就会耐心地把那些碎片拼合在一起。

![屏幕快照 2018-11-01 下午7.46.00.png](https://upload-images.jianshu.io/upload_images/2734090-7ade12ebe158c614.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

这些模块之间同样如此,它们依靠那些凸起和凹陷联系在一起,最终组合成一个完整的程序,这样的过程称为——链接。

这样基于符号的模块化,使得链接过程在整个程序开发中显得十分重要和突出…..

2、下面就静态链接,进行分析。 

1.链接:“组装”模块的过程。 

2.链接的内容:把各个模块之间相互引用的部分都处理好,使得各个模块之间能够正确地衔接。(就像拼图,凸起和凹槽的位置一定一一对应,否则…) 

3.链接的过程:地址和空间的分配、符号决议(也叫“符号绑定”,倾向于动态链接)和重定位 

以gcc编译器为例,看基本的链接过程:

![屏幕快照 2018-11-01 下午7.46.30.png](https://upload-images.jianshu.io/upload_images/2734090-b9a224c8e4d2f657.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

.c文件经过编译器、汇编器之后得到目标文件.o,目标文件再与库进行链接得到可执行文件.out。 

库其实就是一组目标文件的打包,这些目标文件中都是一些常用的代码。

我们在fun.c模块中定义了函数foo(),在main.c模块中引用了foo()函数,在编译过程当中,编译器并不知道main.c中foo()的地址,所以将调用foo()的指令的目标地址部分搁置, 

等到了链接的阶段,链接器会去找到foo()定义的那个模块,在main.o中填入正确的函数地址,这个修改地址的过程被叫做“重定位”,每个被修正的地方叫“重定位入口”。

![屏幕快照 2018-11-01 下午7.46.54.png](https://upload-images.jianshu.io/upload_images/2734090-4c801919176cac0c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

以上就是一个程序从源代码到可执行程序的大致过程,这是根据《程序员的自我修养——链接、装载与库》来整理的,有兴趣的小伙伴可以自己去琢磨琢磨~

免费的iOS SDK和ipa加固和苹果审核被拒群:289533769,群里有免费的iOS SDK和工程的混淆加固工具,每天都分享苹果最新提审过包策略,欢迎大家进来一起交流一起进步一起过包!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342