被隐藏的细节:编译和链接过程

简介: 被隐藏的细节:编译和链接过程

对于平常的应用程序开发,我们很少去关注编译和链接过程,通常开发环境都是集成开发环境IDE做了。IDE一般都将编译和链接过程一步完成,通常将这种编译和链接并到一起的过程成为构建(build) 即使使用命令行编译,基本上也是一条命令,优化了其他的过程。那么,被隐藏的过程到底有哪些呢?


被隐藏的过程



image.png


一个 gcc 的编译过程大致如上图。可以分为以下几步:


  • 预编译


  • 编译


  • 汇编


  • 链接


那么,每个阶段具体又做了哪些工作呢?


预编译


预编译过程主要处理哪些源代码文件中以“#”开始的预编译指令。比如

“#include”、"#define"等,主要处理规则如下:


  • 将所有的“#define”删除,并且展开所有的宏定义。


  • 处理所有条件预编译指令,比如“#if”、“ifdef”、“#elif”、
  • “#else”、"#endif"等。


  • 处理 "#include" 预编译指令,将被包含的文件插入到该预编译指令的位置。注意,这个过程是递归进行的,也就是说被包含的文件可能还包含其他文件。头文件包含不能滥用,特别是交叉包含


  • 删除所有的注释 "//" 和 "/**/"


  • 添加行号和文件名标识,比如#2 "hello.c" 2,以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能显示行号。__LINE__ 这个宏 ,在这个阶段就已经生效


  • 保留所有的 #pragma 编译器指令,因为编译器要使用它们。pragma 这个宏可以在编译阶段调试代码,确定程序分支


经过预编译后,会得到一个 .i 文件,这个文件不包含任何宏定义,所有的宏都已经被展开,并且包含的文件也被插入到 .i 文件中。


预编译作用:确定宏或者头文件包含是否正确。当我们无法确认时,可以通过预编译后的文件来确定问题。 预编译用法:使用gcc 的 -E 选项 用法


gcc -E hello.c -o hello.i    /* pc */
mips-linux-gnu-gcc -E hello.c -o hello.i /* 嵌入式平台 */

代码示例


image.png


预编译


image.png


"#pragma" 的用法暂时不介绍,留待后续


编译


编译过程就是把预处理完的文件进行一些列词法分析、语法分析、语义分析及优化后生成相应的汇编代码文件,这个过程往往是我们所说的整个程序构建的核心部分。


现代版的 gcc 把预编译和编译两个步骤合并成一个步骤,使用一个叫做cc1的程序来完成这两个步骤。对于C++来说是 cc1plus, Objective-C 是cc1obj,Java 是jc1。所以实际上 gcc 这个命令只是这些后台程序的包装,它会根据不同的参数要求去调用预编译程序cc1、汇编器as、链接器ld


用法使用 gcc -S 选项


gcc -S hello.i -o hello.s
mips-linux-gnu-gcc -S hello.i -o hello.s/* 嵌入式平台 */


我们以最简单的hello world程序演示


image.png


截取部分代码:注意gcc -O3 会优化掉一些细节


image.png


汇编


汇编器是将汇编代码转变成机器可以执行的指令,每一个汇编语句几乎对应一条机器指令。汇编过程我们可以调用汇编器as 来完成:


as hello.s -o hello.o
mips-linux-gnu-as hello.s -o hello.o


或者通过gcc -c 选项


gcc -c hello.s -o hello.o
mips-linux-gnu-gcc -c hello.s -o hello.o/* 嵌入式平台 */


经过汇编会得到目标文件hello.o(Object File)


链接


链接过程,是一个比较复杂的过程。链接过程主要包括了以下步骤:


  • 地址和空间分配(Address and Storage Allocation)


  • 符合决议(Symbol Resolution)


  • 重定位(Relocation)


注释:符合决议有时候又叫做符号绑定(Symbol Binding)、名称绑定(Name inding。”决议“更倾向于动态链接,”绑定“更倾向于动态链接。我们通过gcc -v 可以打印编译的详细信息。


最基本的静态链接过程如下:


image.png


链接过程分析:


image.png


这里的collect2 其实就是ld的封装。


image.png


抽象出来主要的命令


image.png


通过以上两种方式都可以手动将我们汇编的目标文件hello.o 链接成一个可执行程序a.out


说明:整个链接过程比较复杂,通过gcc -v 获取详细链接过程,从而分析。


如果把所有的路径都省略掉,那么上面的命令就是:


ld -static crt1.o crti.o crtbegin.o hello.o
--start-group -lgcc -lgcc_eh -lc --end-groud
crtend.o crtn.o


crt1.0 crti.o、crtbegin.o cretend.o crtn.o 这几个库表示 glibc 辅助运行库(C RunTime Library)


这5个目标文件的作用分别是启动、初始化、构造、析构和结束,它们通常会被自动链接到应用程序中。这里暂时不做过多介绍。


总结


本文以gcc 为列,介绍了一个应用程序从源代码到可执行程序的过程。主要分为


  • 预编译; gcc -E hello.c -o hello.i


  • 编译:gcc -S hello.i -o hello.s


  • 汇编:gcc -c hello.s -o hello.o/as hello.s -o hello.o


  • 链接:ld *.o hello.o


整个编译过程:又包含扫描、语法分析、语义分析、源代码优化和目标代码优化。这里不做过多介绍。链接又分为静态链接和动态链接,限于篇幅,留待后续更新。

预编译和汇编在gcc里,使用cc1合成一步,ld 通常被封装成collect2程序,事实上最终调的还是ld。gcc 通过不同的参数选项,事实上,最终还是离不开编译器(cc1)、汇编器(as)、链接器(ld)


限于篇幅,文章其他知识点待后续有空再更新。比如:#pragma 的用法;编译过程详解;目标文件和可执行文件有什么区别,为什么要有链接过程?crt1.0 crti.o 这些库到底是干什么用的等等。感兴趣的朋友可以自行了解学习。

延申阅读《程序员的自我修养,链接、装载与库》、《编译原理》

相关文章
|
机器学习/深度学习 算法 数据可视化
【机器学习】十大算法之一 “K-means”
k-means算法早在1957年就被发明了,最早由J. MacQueen提出。后来,Lloyd(1982年)、Hartigan(1975年)、Forgy(1965年)等学者对此算法进行了修正和改进。这个算法已被广泛应用于数据挖掘、模式识别、图像处理等领域,它可以用来识别数据集之间的模式,因此是一种十分实用的机器学习算法。本篇文章介绍了k-means算法,一种常见的聚类算法。我们详细讲解了该算法的发展史、原理、功能以及示例代码。
924 0
【机器学习】十大算法之一 “K-means”
|
3月前
|
机器学习/深度学习 算法 数据可视化
从另一个视角看Transformer:注意力机制就是可微分的k-NN算法
注意力机制可理解为一种“软k-NN”:查询向量通过缩放点积计算与各键的相似度,softmax归一化为权重,对值向量加权平均。1/√d缩放防止高维饱和,掩码控制信息流动(如因果、填充)。不同相似度函数(点积、余弦、RBF)对应不同归纳偏置,多头则在多个子空间并行该过程。
327 6
|
3月前
|
JSON 安全 生物认证
WhatWeb-网站安全扫描指纹识别
WhatWeb 是一款网站指纹识别工具,用于快速识别目标网站的 Web 服务器类型、CMS、脚本语言、中间件及可能存在的漏洞信息,常用于渗透测试与安全审计。
248 1
|
8月前
|
自然语言处理 安全 程序员
程序员推荐的12款实用模板免费的WordPress主题
本文介绍了12款实用的免费WordPress主题,包括Sydney、PopularFX、Zakra等,涵盖企业、博客、美食等多种风格。这些主题功能丰富,如自定义布局、预制模板、AMP兼容等,适合不同需求的用户。每款主题均有精美预览图展示,建议收藏以备后续使用。更多主题可访问ztmao.com。
422 2
程序员推荐的12款实用模板免费的WordPress主题
|
前端开发 Java 应用服务中间件
计算机Java项目|基于SpringBoot的在线视频教育平台的设计与实现
计算机Java项目|基于SpringBoot的在线视频教育平台的设计与实现
306 0
|
存储 Ubuntu Linux
2024全网最全面及最新且最为详细的网络安全技巧 (三) 之 linux提权各类技巧 上集
在本节实验中,我们学习了 Linux 系统登录认证的过程,文件的意义,并通过做实验的方式对 Linux 系统 passwd 文件提权方法有了深入的理解。祝你在接下来的技巧课程中学习愉快,学有所获~和文件是 Linux 系统登录认证的关键文件,如果系统运维人员对shadow或shadow文件的内容或权限配置有误,则可以被利用来进行系统提权。上一章中,我们已经学习了文件的提权方法, 在本章节中,我们将学习如何利用来完成系统提权。在本节实验中,我们学习了。
|
机器学习/深度学习 算法 固态存储
深度学习算法工程师面试问题总结| 深度学习目标检测岗位面试总结
本文给大家带来的百面算法工程师是深度学习目标检测岗位面试总结,文章内总结了常见的提问问题,旨在为广大学子模拟出更贴合实际的面试问答场景。在这篇文章中,我们还将介绍一些常见的深度学习目标检测面试问题,并提供参考的回答及其理论基础,以帮助求职者更好地准备面试。通过对这些问题的理解和回答,求职者可以展现出自己的深度学习目标检测领域的专业知识、解决问题的能力以及对实际应用场景的理解。同时,这也是为了帮助求职者更好地应对深度学习目标检测岗位的面试挑战,提升面试的成功率和竞争力。
|
开发框架 运维 前端开发
构建一体化运维平台的八大功能
【6月更文挑战第6天】构建一体化运维平台的关键8个基本功能。
程序技术好文:欧奈尔的RPS曲线的编制方法(陶博士原创)
程序技术好文:欧奈尔的RPS曲线的编制方法(陶博士原创)
1042 0
|
JavaScript 前端开发 数据安全/隐私保护
JS中使用Cookie实现记住密码以及设置密码过期时间
JS中使用Cookie实现记住密码以及设置密码过期时间
445 0

热门文章

最新文章