微速讯:详解源文件编译链接至可执行程序的每一步
前言
本文利用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 合并段表
在源文件经过编译过程后文件后缀变为o
或obj
后,其内部的代码已经变成二进制。
此时,文件会将内部的二进制代码按类型
划分成许多部分,每一部分就被称为一段。
如图:
前文我们说到,多个目标文件经过链接器后整合为一个独立而完整的文件,因此链接中合并段表的意思就是把多个目标文件中对应的段,合并在一个目标文件内。
II 符号表的合并
顾名思义,将每个目标文件中的符号表合并成一个目标文件的符号表。
III 符号表的重定位
如果在写代码时发生函数定、声明、使用等不在同一源文件等情况,那么多个目标文件的符号表中可能都会有相同的函数名及无效的地址,像这样:
如上图,在两个文件中都有add的存在,那么,在head.obj
和源.obj
的符号表中都会有收录add。
但因源.c
中没有对add进行实现,因此在汇总源.c
的符号表时,其地址会被填入一个无效的地址。
在链接过程中,链接器不仅会对符号表合并,也会将多余的符号删除,同时将每个符号的地址都定位为所有地址中有效的那一个。
IIII 找不到符号报错
如果在写代码时不小心将函数名写错了,像这样:
那么由于在head.h
汇总符号表时找不到代码实现,就会把Add
的地址赋为一个无效的地址,像这样:
名 | 址 |
---|---|
Add | 0X00000000 |
add | 0X0012FF40 |
但是,在符号表的重定位时,也没有重定位Add的有效地址,那么链接就无法完成,就会报出典型的错误:
PS:函数声明extern
的作用就是告诉编译器,遇到无法解释的符号先别急着报错,后面会有定义的。
四、全文总结
多个源文件经过预处理(头文件包含、宏定义替换、注释的删除),编译(语法分析、词法分析、词义分析、符号汇总),汇编(二进制指令翻译、形成符号表)后成为一个目标文件。
多个目标文件在链接库的帮助下完成合并段表,符号表合并,符号表重定位后整合为一个目标文件。
到最后变成一个可执行的exe文件。
感谢您的阅读与耐心~
-
微速讯:详解源文件编译链接至可执行程序的每一步
2023-02-10 -
即时:摩托罗拉z3_moto_z3
2023-02-10 -
微软表示视觉效果不会损害Windows 11的性能
2023-02-10 -
台州新型冠状病毒肺炎疫情:2月10日台州疫情最新消息今天数据统计情况通报
2023-02-10 -
新闻源发表的优势主要有哪些?
2023-02-10 -
苏剑:为何中国多省份经济增长预期定为5%左右或更高?
2023-02-10 -
世界热议:神都夜行录猜礼物
2023-02-10 -
体重体脂秤品牌推荐榜 体重体脂秤哪个牌子好-全球速看
2023-02-10 -
微软加大对人工智能领域投资|每日视讯
2023-02-10 -
开展赞助活动需要注意哪些事项?公共关系_开展赞助活动需要注意哪些事项_即时
2023-02-10 -
中高职教育贯通培养模式 今年上海增设30个专业
2023-02-10 -
qq空间怎么克隆
2023-02-10 -
天天播报:美尔雅:2月9日获融资买入308.98万元
2023-02-10 -
桐庐巴比松米勒庄园|焦点播报
2023-02-10 -
环球报道:逆商百度百科_逆商指的什么
2023-02-10 -
什么是电压的作用效应_什么是电压
2023-02-10 -
天天百事通!007名字的由来
2023-02-10 -
9连跌*ST奇信发异动公告,或难改退市命运:全球焦点
2023-02-09 -
今日热点更新 台湾地震已致1死164伤 当地目前形势如何??
2023-02-09 -
阳了应该怎么办-阳性感染者如何用药 02月09日20时河南安阳疫情数据
2023-02-09 -
西安工地挖出古墓群 工地挖出古墓怎么办_世界快看点
2023-02-09 -
今日热闻!士官学校录取分数线2022各省汇总_含44所院校名单,2023参考
2023-02-09 -
恒大高新董秘回复:公司目前尚未研发生产“固态电池”,但积极推进新能源产业布局和发展是公司战略方向|天天动态
2023-02-09 -
以精品致经典,美菱全无间冰箱惊艳亮相京东星火计划_实时焦点
2023-02-09 -
中国第一座佛教寺院 中国第一座佛教寺院是白马寺 当前热点
2023-02-09 -
湖南首批创新型中小企业来了 2460家企业上榜-全球热资讯
2023-02-09 -
今我来思雨雪霏霏的意思 今我来思雨雪霏霏的意思简述
2023-02-09 -
热推荐:南方红豆杉种植技术_南方红豆杉
2023-02-09 -
【强信心开新局 确保实现开门红】晋城城区16条措施激发经济活力
2023-02-09 -
当前最新:女娲补天的故事50字左右_女娲补天的故事50字
2023-02-09
-
守住网络直播的伦理底线
2021-12-16 -
石窟寺文化需要基于保护的“新开发”
2021-12-16 -
电影工作者不能远离生活
2021-12-16 -
提升隧道安全管控能力 智慧高速让司乘安心
2021-12-16 -
人民财评:提升消费体验,服务同样重要
2021-12-16 -
卫冕?突破?旗手?——武大靖留给北京冬奥会三大悬念
2021-12-16 -
新能源车险专属条款出台“三电”系统、起火燃烧等都可保
2021-12-16 -
美术作品中的党史 | 第97集《窗外》
2021-12-16 -
基金销售业务违规!浦发银行厦门分行等被厦门证监局责令改正
2021-12-16 -
保持稳定发展有支撑——从11月“成绩单”看中国经济走势
2021-12-16