源文件如何一步步到可执行程序【程序员必修课】
文章目录
- ⚽引入
- ⚽预处理
- ⚽编译(生成汇编代码)
- ⭐符号汇总
- ⭐汇编(生成二进制机器码)
- ⚡ 符号表简述
- ⚡ 链接(生成可执行程序)
- ⚽总结
⚽引入
想必大家编写的第一个程序都是hello world,到后来编写越来越多的程序,那我们是否了解一个源文件是如何编译链接为.exe的可执行程序的呢?下面我们就来深入了解一下
在C/C++中,一个程序要运行起来,要经历四个阶段:预处理、编译、汇编、链接,最后形成可执行程序
由于windows下的vs系列是集编辑器、编译器、调试器等为一体的IDE环境,所以我们在Linux下演示
⚽预处理
这里在test.c文件中编写了一个简单的测试代码
选项-E
:让 gcc 在预处理结束后停止编译过程。只进行预处理,不会生成对应的文件,所以需要-o选项输出到指定文件
选项-o
:文件输出到文件,也就是将结果输出到指定文件
gcc -E test.c -o test.i #将test.c预处理后的结果输出到test.i文件
所以预处理阶段完成了:
头文件展开、去注释、宏替换、条件编译
且是先执行去注释,再执行宏替换的
⚽编译(生成汇编代码)
选项-S
: 让gcc在编译阶段结束后停下来
gcc -S test.i -o test.s #将编译阶段结束后的结果输出到test.s的文件
这里由于预处理后printf函数在main函数外调用所以报错,所以这里我们错误的调用printf函数就会在编译阶段报错
而汇编阶段的主要工作就是进行:词法分析、语法分析、语义分析、符号汇总,最后将c代码优化后变为汇编代码
那为什么要进行这些语法语义分析呢?
如果我们要将下面的英语翻译成翻译成汉语,首先需要判断这些字符串哪些能组成一个单词,然后在判断单词是否正确以及每个单词的意思,最后得到对应的语义。
而编译器也是如此,因为程序本质上就是一定字符集上的一字符串
,所以需要规定哪样的字符串是一个单词符号,检查代码的规范性、是否有语法错误等,还是需要判断单词符号的语法意义,是while循环,还是if判断或是其他语义,最后还有相应的优化生成中间代码最后翻译成汇编,当然这个过程是非常复杂的
这里我们重新定义两个文件进行演示
gcc test.c Add.c -S #汇编阶段结束后停止编译,生成test.s和Add.s文件
可以发现test.s和Add.s文件都是汇编代码
⭐符号汇总
符号汇总是非常重要的,最终是为了在汇编阶段形成符号表
,符号表包含名字(标识符)和此名字的有关的一系列信息,然后在链接阶段进行符号合并和重定向。
因为printf函数和Add函数的定义并不在test.c文件中,所以不能生成地址
⭐汇编(生成二进制机器码)
gcc -c test.s Add.s #程序编译到汇编阶段后停下来,将.s文件转换为.o的二进制目标文件
汇编阶段:将汇编文件转换成二进制文件,生成.o的目标文件(类似于windows下的.obj目标文件)且是可重定向目标文件,不可以直接执行,需要通过链接后才能变成可执行程序
可以看到test.o和Add.o二进制文件都是乱码
那么有的小伙伴就疑惑了,不应该是二进制吗?为什么都是乱码?
在linux下目标文件是以elf格式组织的,而我们通过vim编辑器查看是以文本形式查看的,所以都是乱码
readelf命令 #查看elf格式的文件信息
readelf -a [目标文件] #查看elf文件的所有信息
我们通过readelf命令可以看到Add.o和test.o文件的段表,链接的时候就需要合并段表
以及Add.o和test.o文件的符号表
在test.o中,main函数的size是67,而Add和printf函数的size都是0,因为这两个函数只有声明没有定义,所以需要通过下一步链接找到对应的函数,且它们是没有地址的,函数只有定义了才有地址
在Add.o文件定义了Add函数,所以size为20
objdump -S [文件名] #反汇编目标文件或可执行程序的命令
⚡ 符号表简述
⚡ 链接(生成可执行程序)
链接完成:合并段表,符号表的合并和重定位
在汇编阶段形成二进制文件后为什么不能直接执行,还需要链接呢?
因为要将程序中的各种功能模块组合起来,将代码中的函数调用、外部数据和库关联起来,比如通过包含头文件将相关的库链接起来,简单来说程序运行需要的目标文件和所依赖的库链接起来才能形成可执行的文件
前面我们在预处理阶段看到头文件stdio.h的展开,里面存放的只是一些库的所在路径,函数的声明等,那我们就需要在链接阶段链接库中对应的目标文件,以及我们在其他文件定义的函数
而可执行程序只有一个,所以将多个.o的目标文件链接起来,合并段表以及进行符号表的合并和重定位,链接库,最后形成可执行程序
而链接阶段就要涉及动态库、静调库以及动态链接和静态链接的概念了,我将在下一篇文章中介绍
⚽总结
今天的分享到这里结束了,希望的的位置对你有所帮助,欢迎
源文件如何一步步到可执行程序【程序员必修课】相关推荐
- 程序员必修课:为什么非要用Python做数据分析?Excel不好吗?
日本最大的证券公司之一野村证券首席数字官马修·汉普森,在Quant Conference上发表讲话:"用Excel的人越来越少,大家都在码Python代码." 甚至直接说:&quo ...
- 程序员必修课:为什么非要用 Python 做数据分析?Excel 不好吗?
伴随着移动互联网的飞速发展,越来越多用户被互联网连接在一起,用户所积累下来的数据越来越多,市场对数据方面人才的需求也越来越大,由此也带火了如数据分析.数据挖掘.算法等职业. 数据分析师就业待遇和发展前 ...
- 程序员必修课--sql思维举重训练
写sql是程序员基本功课,找工作面试一般必有sql题,实际工作中对sql的需求更是千变万化,所以掌握好sql对于一个程序员来说是件非常重要的事情.本文通过一个简单易懂的关系(学生/课程/成绩关系)尽量 ...
- 高级程序员必修课--sql思维举重训练
出处:http://blog.csdn.net/lk_blog/article/details/7585540 写sql是程序员基本功课,找工作面试一般必有sql题,实际工作中对sql的需求更是千变万 ...
- 高级程序员必修课--sql思维举重训练 .
写sql是程序员基本功课,找工作面试一般必有sql题,实际工作中对sql的需求更是千变万化,所以掌握好sql对于一个程序 员来说是件非常重要的事情.本文通过一个简单易懂的关系(学生/课程/成绩关系)尽 ...
- 程序员必修课-sql语句
sql是硬伤,以下这篇文章于我真是饕餮大餐,享受之余转来分享~~ 写sql是程序员基本功课,找工作面试一般必有sql题,实际工作中对sql的需求更是千变万化,所以掌握好sql对于一个程序员来说是件非常 ...
- 90后iOS开发者的出路,如何规划30岁前的自己(程序员必修课)
最近发生了一些和我们没有直接关系但是有间接关系的事情.比如华为"清洗"高龄基层员工,比如游戏公司2号员工拿不到股份而离职.先不说事实到底如何,起码很多码农是心有戚戚焉. 最近一年多 ...
- sql -高级程序员必修课
--创建表 create table T_STUDENT(sno NUMBER not null, sname VARCHAR2(30), sdree VARCHAR2(50), sage N ...
- 20年无人能破的RSA算法发明人出的密码学难题, 竟被这个无名程序员3年破解!...
来源 | WIRED 编译 | Guoxi 责编 | Aholiab 出品 | 区块链大本营(blockchain_camp) 1994 年 4 月,作为麻省理工学院计算机科学实验室成立 35 周年的 ...
最新文章
- wxWidgets:制作渲染循环
- POJ1179 Polygon 【例题精讲】
- Express框架使用以及数据库公共操作类整理(Win7下的NodeJs)
- JS获取url参数,主域名等方法
- Linux centos7系统下JBoss7.1的部署安装
- 扩展欧几里得算法的证明
- ads pspice 导入_ADS中使用pspice模型
- ModuleNotFoundError: No module named ‘项目同名.settings’
- Windows命令:tracert
- 输入一个十进制整数,分别输出其二进制、八进制、十六进制字符串
- mybatis-plus配置(包含分页插件)
- 批量安装/卸载/fore-stop apk的脚本
- 微信小程序iphone7设备下跳转h5页面失败,h5页面显示白屏,加载报错,其他页面正常显示
- PCB板的绘制原来是这样完成的——布线
- deep linux用ntfs,deepin开机挂载ntfs分区和ext4分区教程
- Vue在线编译器:vue-running
- 虚拟研讨会:如何设计好的RESTful API?
- 计算机专业择偶标准,爱情句子:说来说去我的择偶标准也就一个字——你
- 【网络攻击手段之----- DDOS攻击】
- 2023跨年烟花代码HTML5夜景放烟花绽放动画效果
热门文章