C++程序的编译链接过程

news2025/1/24 1:21:51

一、预处理

(1) 将所有的#define删除,并且展开所有的宏定义

(2) 处理所有的条件预编译指令,如#if、#ifdef

(3) 处理#include预编译指令,将被包含的文件插入到该预编译指令的位置。

(4) 过滤所有的注释

(5) 添加行号和文件名标识。

需要注意的是,对于#pragma预编译指令不一定是在这个阶段执行的,因为#pragma link就是在链接阶段才会执行的。

二、编译

(1) 词法分析:将源代码的字符序列分割成一系列的记号。

(2) 语法分析:对记号进行语法分析,产生语法树。

(3) 语义分析:判断表达式是否有意义。

(4) 代码优化:比如内联函数、合并代码分支、公共子表达式消除等。

(5) 目标代码生成:生成汇编代码并且进行优化。

三、汇编

将汇编代码转变成机器可以执行的指令(全部在.text段里面),最终产生.o文件或者.obj文件等二进制可重定位的目标文件。

四、链接

将不同的源文件产生的目标文件和静态库文件进行链接,从而形成一个可以执行的程序。

链接的过程主要分为两部分

(1)将所有.o文件的文件段合并,比如main.o的.text和sum.o的.text合并为.exe的.text,然后合并符号表段(.section table段),并进行符号解析,如果解析成功,就给对应的符号分配虚拟地址,否则就会报错(符号未定义或者符号重定义),需要注意的是,如果从一个.cpp文件通过extern引用另一个.cpp文件的变量或者函数,那么符号解析也会将这个函数和变量写入这个.cpp对应的.o文件的符号表中,但是段位置会显示为undefine而不是.text或者.data等文件段。

(2)进行符号的重定位,由于.cpp文件在汇编阶段就已经产生了.o文件,也就是说此时的.text中已经存在了汇编指令,.section table也有了符号,但是由于符号表中的符号没有分配虚拟内存,所以此时符号表中所有的符号地址默认为0,经历了过程一之后,符号分配了虚拟地址,这时候就需要对这些.text段的汇编指令里面对应符号的地址从0重定位到分配的虚拟地址。

实例说明

比如我们有一个main.cpp

#include<iostream>
using namespace std;
extern int globaldata;
int sum(int,int);
int localdata=10;
int main()
{
int a=globaldata;
int b=localdata;
int ret=sum(a,b);
cout<<ret<<endl;
return 0;
}

还有一个sum.cpp

int globaldata=10;
int sum(int a,int b)
{
return a+b;
}

 很显然,我们通过extern在main.cpp中引用了sum.cpp的全局变量globaldata和函数sum。

在Linux上进行编译,可以生成对应的.o文件。

g++ -c main.cpp sum.cpp

  

然后可以通过objdump指令查看这些.o文件的具体信息。

比如查看.o文件的符号表信息

objdump -t sum.o

 

        从这里可以发现,我们的globaldata和sum函数在符号表中都有对应的符号 ,比如sum函数对应的符号就是_Z3sumii,这个是通过sum函数的名称和它的参数列表共同生成的,具体生成机制大家可以自己去了解哈。

这个是main.o的符号表。

        就和我们上面所说的一样,由于globaldata和sum函数是main.cpp从sum.cpp外部引用过来的,所以它们的 段位置都是UND(undefine),而其他main自己的符号都是有对应的文件段的,而且我们可以发现main函数和localdata都是全局符号(g),代表它们可以其他文件引用。

除此之外,我们还可以通过objdump指令,查看一个.o文件由哪些文件段组成。

objdump -h sum.o

main.o的段组成。

         可以发现.o文件的组成格式是统一的,这也是为什么链接步骤的第一步的合并文件段可以进行,正是因为.o文件都有相对应的文件段所以可以合并啊,当然合并之后就是.out文件了。

通过g++将main.cpp和sum.cpp编译链接为可执行文件test.out。

再查看.out文件的组成格式。

readelf -t test

 显然.out文件同样是有.text和.data等文件段的,这些就是通过.o文件对应的文件段合并而来的。

查看.out文件的elf文件头 

readelf -h test

 

这个入口点地址就是main函数的第一行代码的偏移地址,也就是0x4006a0。

 查看test.out的汇编指令

objdump -S test

找到.text的汇编指令段,我们知道.text段存放的就是程序代码的汇编指令,所以main函数什么的都在这里面,这个4006a0就是main函数的第一行代码地址,也是我们程序的入口地址。 

        其实从这个链接过程再结合进程的虚拟内存地址,我们基本可以推断出.o/.obj文件和.out/.exe文件的基本组成格式了。

        .obj文件又叫作二进制可重定位的目标文件,它是由一个elf文件头和很多个文件段组成的,比如.text和.data等等,由于.exe文件是由若干个.obj文件链接而成的,所以.exe文件的组成和.obj文件基本一致,只是.exe的各个文件段都是.obj文件对应的文件段合并而来的,但是有一点不同的是,.exe文件它有一个program headers的文件段,这个文件段规定了.exe文件要把哪些文件段加载到内存中,毕竟不是所有文件段都需要加载进入内存,像符号表什么的就不需要,但是.text和.data等就需要,另外需要注意的是,一个cpp程序之所以会从main函数的第一行代码开始执行,是因为.exe文件的elf文件头规定了程序的入口地址,这个入口地址就是main函数第一行代码的地址。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1978010.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

html+css 实现hover边框彩色流动

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享htmlcss 绚丽效果&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 文…

人工智能深度学习系列—深入探索IoU Loss及其变种:目标检测与分割的精度优化利器

文章目录 1. 背景介绍2. Loss计算公式3. 使用场景4. 代码样例5. 总结 1. 背景介绍 在深度学习的目标检测和分割领域&#xff0c;评估预测结果与真实标注之间的一致性是提升模型性能的关键。IoU Loss&#xff08;Intersection over Union Loss&#xff09;及其变种损失函数&…

【人工智能五】人工智能基础习题

文章目录 壹. 内容补充一. VR&#xff0f;AR&#xff0f;MR的区别1. 三者概念2. 区别 二. 深度学习重要算法及人物介绍1. 反向传播算法2. 卷积神经网络 贰. 习题精选1一. 选择二. 判断题三. 填空题四. 简单题1. 综合2. 深度学习与神经网络 壹. 内容补充 一. VR&#xff0f;AR&…

人工智能与机器学习的相关介绍

文章目录 人工智能的发展历程人工智能与机器学习关系图谱数据处理机器学习ML和深度学习DL的区别人工智能按照学习方式划分监督学习算法无监督学习算法总结 人工智能的发展历程 重要的时间点了解一下&#xff1a; 早在1950年人工智能就已经开始兴起 1997年deep blue战胜了人类国…

一款功能强大的屏幕演示工具,免费版足够使用!

鼠标换肤 | 屏幕画笔 | 放大镜 | 聚光灯 | 屏幕放大 | 倒计时&#xff0c;功能强大的屏幕演示工具 屏幕演示工具适用于Windows平台&#xff0c;特别是Windows 10及以上版本。该软件提供了多种实用功能&#xff0c;包括鼠标换肤、屏幕画笔、放大镜、聚光灯、屏幕放大和倒计时等…

k8s集群的资源发布方式(滚动/蓝绿/灰度发布)及声明式管理方法

目录 1.常见的发布方式 2.滚动发布 3.蓝绿发布 4.实现金丝雀发布&#xff08;Canary Release&#xff09; 5.声明式管理方法 1.常见的发布方式 蓝绿发布:两套环境交替升级&#xff0c;旧版本保留一定时间便于回滚优点&#xff1a;用户无感知&#xff0c;部署和回滚速度较…

基于强化学习算法玩CartPole游戏

什么事CartPole游戏 CartPole&#xff08;也称为倒立摆问题&#xff09;是一个经典的控制理论和强化学习的基础问题&#xff0c;通常用于测试和验证控制算法的性能。具体来说&#xff0c;它是一个简单的物理模拟问题&#xff0c;其目标是通过在一个平衡杆&#xff08;倒立摆&a…

Cesium初探-坐标转换

Cesium的坐标系分三种&#xff1a;屏幕坐标、笛卡尔空间直角坐标、地理坐标。 屏幕坐标 屏幕坐标系是一个是平面直角坐标系&#xff0c;即二维笛卡尔坐标系&#xff0c;屏幕左上角为原点&#xff08;0,0&#xff09;&#xff0c;单位为像素值&#xff0c;屏幕水平方向为X轴&a…

Python | SyntaxError: invalid syntax 深度解析

Python | SyntaxError: invalid syntax 深度解析 在Python编程中&#xff0c;SyntaxError: invalid syntax是一个常见的错误&#xff0c;它表明Python解释器在尝试解析代码时遇到了语法问题。这个错误通常是由于代码中存在拼写错误、缺少符号&#xff08;如括号、冒号或逗号&a…

Java中的Map(如果想知道Java中有关Map的知识点,那么只看这一篇就足够了!)

前言&#xff1a;在Java编程语言中&#xff0c;集合框架&#xff08;Collection Framework&#xff09;提供了一系列用于存储和操作数据的接口和类。其中&#xff0c;Map和Set是两个非常重要的接口&#xff0c;分别用于存储键值对和无重复元素的集合。 ✨✨✨这里是秋刀鱼不做梦…

Nerd Fonts

文章目录 关于 Nerd Fonts重要告示TL;DR字体的各种下载选项 特点 Glyph Setsshell中的图标名称 修补字体Variations 字体安装Option 1: Release Archive DownloadOption 2: Homebrew FontsOption 3: Unofficial Chocolatey or Scoop RepositoriesOption 4: Arch Extra Reposito…

AI在医学领域:医学成像中针对深度神经网络(DNN)的对抗性攻击及其防御策略

关键词&#xff1a;对抗性攻击、医学图像、深度神经网络、模型安全、鲁棒性 机器学习&#xff08;ML&#xff09;是医学领域快速发展的一个分支&#xff0c;它利用计算机科学和统计学的方法来解决医学问题。众所周知&#xff0c;攻击者可能通过故意为机器学习分类器创建输入来…

C++11 包装器

1.function包装器 1.1 概念介绍 ret func(x); 上面 func 是什么呢&#xff1f;那么 func 可能是函数名&#xff0c;函数指针&#xff0c;函数对象 ( 仿函数对象 )&#xff0c; 也可能是lamber 表达式对象&#xff0c;这些都是可调用的类型。 函数包装器&#xff0c;也称为函…

comfyui老照片修复工作流,直接复制到comfyui中即可使用

ComfyUI是一个基于web的图形用户界面,用于直观地构建和运行AI模型流程。它特别适合于使用Stable Diffusion等模型进行图像生成任务。然而,ComfyUI本身并不直接提供老照片修复的功能,但你可以通过组合不同的节点来实现这一目标。 老照片修复通常涉及到几个关键步骤: 图像去…

人像修复-插件磨皮

破锤和DR5插件磨皮 破锤插件&#xff08;更快磨皮&#xff09;DR5&#xff08;更好保留皮肤纹理&#xff09; 破锤插件&#xff08;更快磨皮&#xff09; 打开方式&#xff1a;滤镜->Imagenomic->Portraiture 磨皮阈值一般控制在10-20之间若环境与肤色接近&#xff0c;容…

PYTHON专题-(3)你应该知道python内置函数

abs() 函数返回数字的绝对值。dict() 函数用于创建一个字典。help() 函数用于查看函数或模块用途的详细说明。min() 方法返回给定参数的最小值&#xff0c;参数可以为序列。max() 方法返回给定参数的最大值&#xff0c;参数可以为序列。round() 方法返回浮点数 x 的四舍五入值&…

【独家原创】基于APO-Transformer多变量回归预测【24年新算法】 (多输入单输出)Matlab代码

【独家原创】基于APO-Transformer多变量回归预测【24年新算法】 &#xff08;多输入单输出&#xff09;Matlab代码 目录 【独家原创】基于APO-Transformer多变量回归预测【24年新算法】 &#xff08;多输入单输出&#xff09;Matlab代码效果一览基本介绍程序设计参考资料 效果一…

中国数字孪生进入爆发期,平台级产品决定市场高度

MIT 教授 Geoffrey Parker在《平台革命》中认为&#xff0c;平台正在吞噬整个世界&#xff0c;平台赋予开放的参与式架构&#xff0c;设定合理的参与规则&#xff0c;通过创新的产品、服务为所有参与者创造价值。 与现实世界类似&#xff0c;在数字孪生世界中&#xff0c;数字…

分享5款.NET开源免费的Redis客户端组件库

前言 今天大姚给大家分享5款.NET开源、免费的Redis客户端组件库&#xff0c;希望可以帮助到有需要的同学。 StackExchange.Redis StackExchange.Redis是一个基于.NET的高性能Redis客户端&#xff0c;提供了完整的Redis数据库功能支持&#xff0c;并且具有多节点支持、异步编…

JavaScript基础——Date日期对象常见的用法

Date日期对象 查看Date日期对象的数据类型 创建Date日期对象的实例 获取Date日期对象的属性 设置Date日期对象的属性 日期和时间的比较 获取时间戳 比较时间戳 Date日期对象 JavaScript中的Date类型&#xff0c;提供了一种处理日期和时间的方法&#xff0c;用于创建表示…