资讯 更多 >>
我胡汉三又回来了图片_我胡汉三又回来
1992年,塞族士兵枪杀了无辜的妇女...
北京疾控发布预防流感家庭消毒指南
追踪马斯克私人飞机动向的大学生新...
全球消息!水下迷宫该怎么弄_水下迷宫
压缩分卷文件怎么解压_压缩分卷怎么...
柱形图数据表怎么编辑_柱形图
鼓励的反义词_鼓励的意思_世界热文
天天速看:多肉小说推荐_全是肉的小...
2017年专八考试时间_2017年赚钱好项...
业界更多 >>
环球快讯:工信部:加快电力设备绿色...
天天百事通!欧洲试图发展动力电池...
焦点信息:2022激光聚会活动回顾|AC...
环球热推荐:丹佛斯服贸会携手三大...
天天速递!精彩依旧,图尔克荣获202...
环球速看:运用数字孪生+智能算法,...
世界播报:锂电池快充或将突破技术难关
每日快讯!喜报!清能德创荣获国家级...
天天要闻:腾讯成国内首个获批创新...
环球消息!机器人的仿生之道
看点:广域网:通往可扩展物联网的网关
当前滚动:Kerk专利设计的静音轴套-...
天天时讯:工信部:我国已建成60家...
每日看点!机器人一定要像人吗?实力...
天天信息:移动终端市场遭遇低谷,纷...
【环球聚看点】共筑5G新生态 全面...
快看点丨马斯克:未来十年,新车有...
环球百事通!乘联会:预估8月新能源...
世界时讯:拥抱电气化,汽车动力进...
新消息丨发展燃料动力锂电池和混合...
专题报道 
当前位置: 资讯 > >> 正文
 
详解源文件编译链接至可执行程序的每一步
来源:腾讯云     时间:2023-02-13 09:58:09

前言

本文利用C语言介绍源文件是如何一步一步地编译、链接成为可执行程序的。


【资料图】

一、编译链接总述

编译链接本身分为许多个过程,但从整体上可以概括为以下三点:

程序的每个源文件分别通过编译器的编译,生成对应的目标文件。每个目标文件通过链接器链接在一起,形成一个独立单一而完整的可执行文件。链接时会在链接库内搜索C标准库及程序员个人函数库中的函数,并将其链接至可执行程序。

整体过程如下图所示:

二、编译过程

阶段I 预处理

预处理,又叫预编译,源文件在进入编译器后要首先进行预处理操作,告诉编译器如何预处理的代码被称为预处理指令,常见的有头文件的包含,宏定义等。

经过预处理后的文件后缀会变为i,文件以i为后缀代表其已经过预处理,但未进行下一阶段的编译

1)头文件的包含

在我们写代码时,包含头文件的是必不可少的,而在预处理中:包含头文件的操作等同于拷贝头文件中的代码,随后将源文件中的代码和头文件中的代码一起放入后缀为i的文件中。

预处理前:

预处理后:

相当于将头文件中的代码拷贝至源文件的头部,同时删掉#include"head.h"其效果与下面的代码相同,此时的文件后缀为i

struct MyStruct{int a;int b;};int main(){struct MyStruct s;return 0;}

2)宏定义的替换

在预处理时,源文件中宏定义内容会在i文件中被直接替换。

预处理前:

#include#define MAX 100int main(){int a = MAX;printf("%d\n", a);return 0;}

预处理后:

预处理后MAX会被直接替换为100,同时删除前面的#define MAX 100,其效果与下图代码相同。

3)注释的删除

在预处理时,编译器还会删除//后面的内容以及被/* */包括起来的内容,以便于接下来的编译阶段。

如图:

4)阶段总结

可以看到,不管是头文件、宏定义、还是注释,都是编译器对文本的操作。

因此可以说:预处理阶段是编译器对文本的操作阶段

阶段II 编译

当源文件经过预处理后,便开始第二个阶段——编译,经过编译的文件的后缀将变成s,文件后缀为s代表其已经经过第二阶段的编译,但未进行汇编操作

编译阶段会将C语言代码进行语法分析词法分析词义分析,以及符号汇总

1)主要操作

语法分析:检测是否有语法错误,检测语法格式是否正确等。词法分析:拆解语句或字符为关键字等。语义分析:翻译每条语句或关键字的意义。符号汇总:将代码中涉及的符号进行汇总,以便于在汇编阶段中形成符号表。

2)阶段总结

编译阶段从整体上看是对C语言代码进行分析解读由于该阶段涉及编译的原理,因此只了解大概即可,详见书籍《编译原理》。

阶段III 汇编

当源文件经过第一、二阶段后,便开始第三个阶段——汇编,经过汇编的文件的后缀将变成o或obj,即开头所说的目标文件,文件后缀为o或obj代表其至少已经经过三个阶段的编译

PS:在VS环境下生成的目标文件后缀为obj,在GCC环境下生成的目标文件后缀为o

1)主要操作

将汇编代码翻译成二进制指令。形成符号表。

2)符号表详解

在第二阶段的编译中会将代码中的全局变量函数名等汇总,并在汇编阶段形成类似一张表格。

收集以下代码中的全局变量与函数名:

形成表格:

符号表的详细作用在链接时详细介绍。

...

val

0X0012FF40

add

0X0012FF80

main

0X0012FF20

三、链接过程

链接主要包括合并段表符号表的合并及重定位两大过程。

下面依次介绍。

I 合并段表

在源文件经过编译过程后文件后缀变为oobj后,其内部的代码已经变成二进制。

此时,文件会将内部的二进制代码按类型划分成许多部分,每一部分就被称为一段。

如图:

前文我们说到,多个目标文件经过链接器后整合为一个独立而完整的文件,因此链接中合并段表的意思就是把多个目标文件中对应的段,合并在一个目标文件内

II 符号表的合并

顾名思义,将每个目标文件中的符号表合并成一个目标文件的符号表。

III 符号表的重定位

如果在写代码时发生函数定、声明、使用等不在同一源文件等情况,那么多个目标文件的符号表中可能都会有相同的函数名及无效的地址,像这样:

如上图,在两个文件中都有add的存在,那么,在head.obj源.obj的符号表中都会有收录add。

但因源.c中没有对add进行实现,因此在汇总源.c的符号表时,其地址会被填入一个无效的地址

在链接过程中,链接器不仅会对符号表合并,也会将多余的符号删除,同时将每个符号的地址都定位为所有地址中有效的那一个

IIII 找不到符号报错

如果在写代码时不小心将函数名写错了,像这样:

那么由于在head.h汇总符号表时找不到代码实现,就会把Add的地址赋为一个无效的地址,像这样:

Add

0X00000000

add

0X0012FF40

但是,在符号表的重定位时,也没有重定位Add的有效地址,那么链接就无法完成,就会报出典型的错误:

PS:函数声明extern的作用就是告诉编译器,遇到无法解释的符号先别急着报错,后面会有定义的。

四、全文总结

多个源文件经过预处理(头文件包含、宏定义替换、注释的删除),编译(语法分析、词法分析、词义分析、符号汇总),汇编(二进制指令翻译、形成符号表)后成为一个目标文件。

多个目标文件在链接库的帮助下完成合并段表,符号表合并,符号表重定位后整合为一个目标文件。

到最后变成一个可执行的exe文件。

感谢您的阅读与耐心~

关键词: 汇编语言 编程算法

上一条:汽车疑问解答:汽车点烟器有什么牌子_精选 下一条:情人节前一天夺冠!吴易昺女友乐了,身材修长笑容甜美 收获最好礼物_今日要闻