<三>从编译器角度理解C++代码编译和链接原理
1代码
点击查看代码
**sum.cpp**
int gdata=10;
int sum(int a,int b){
return a+b;
}
**main.cpp**
extern int gdata;
int sum(int , int );
int data=20;
int main(){
int a =gdata;
int b=data;
int ret=sum(a,b);
return 0;
}
1:编译
需要关注的几个点
1: .o 文件的格式组成是什么样子?
2: .exe 文件的组成格式是什么样子?
3: "所有.o文件段的合并 符号表合并后,进行符号解析"
4: "符号的重定位(重定向)"
5: "符号表的输出"=> "符号"
6: 符号什么时候分配虚拟地址?
预编译
以#开头的命令
除#pragma lib -> 链接阶段处理
除#pragma link -> 链接阶段处理
编译
语法分析,语义分析,代码优化 gcc g++
编译后生成相应平台的 汇编代码 X86 和 AT&T
链接
链接所有 .o文件和 静态库文件
.o 文件 主要是由以下组成
elf 文件头
.text
.data
.bss
.symbal
.section table
....
符号表中,在自己文件中定义的,那就是符号定义,如果是引用外部的就 是 "UND"符号引用
符号表中的符号 都没有分配地址,如下图,所以编译过程中,符号是不分配虚拟地址的,是在链接的时候分配
经过了上面的 预编译-》编译-》汇编 各个阶段后 下面开始进入了 链接阶段
main.o 文件 sum.o 文件
上面我们看到 .o 文件是由各个段组成的,所以进入链接阶段的时候
第一步 将各个.o 文件 的各个段合并
main.o 文件的 .text段 与 sum.o 文件的 .text 段合并
main.o 文件的 .data段 与 sum.o 文件的 .data 段合并
main.o 文件的 .bss段 与 sum.o 文件的 .bss 段合并
main.o 文件的 符号表 与 sum.o 文件的符号表 段合并
第二步 非常重要的一点是 在main.o文件的符号表与sum.o文件的符号表段合并的时候,需要进行符号解析。
什么是"符号解析"?
所有对符号的引用,都要找到该符号定义的地方 “符号的引用” 即符号为 UND形式, 要找到该符号定义的地方即要找到该符号是在.text 段中定义还是在.data段中定义,
例如:链接器发现main.o文件的sum函数和gdata是UND形式的,那么链接器会去其他文件中找到sum和gdata的定义,如果没找到,那么链接器报错"符号未定义",
如果链接器找到了多个,那么链接器也会报错 “符号重定义”,所以在整个工程中,全局的名字是不能重名的,否则会产生冲突.
符号解析成功以后 就开始回给所有的符号分配地址
第三步 "符号重定向"
在符号解析成功以后并且给所有的符号分配地址后,需要继续做 "符号重定向"
在我们指令编译汇编生成.O文件的时候,生成的指令中的符号的地址都是用0 代理,如下图
现在我们需要将给符号分配好的地址 将指令中的这些0地址重新修正
现在我看下链接后的情况
符号表情况
指令情况
所以现在我们知道 “符号是在什么时候分配地址”, 在链接第一阶段 符号解析成功后
可执行文件 a.out 和 .O文件的组成方式很像,但是还是有一点区别
在a.out 可执行文件中 增加了 “program headers” , a.out 文件中不是 所有的内容都会加载到内存中的,这个
"program headers"中指定了需要加载哪些到内存中
上图中的 有两个load 就是需要加载到内存中的.
下面我们再看看可执行程序加载到内存过程
<三>从编译器角度理解C++代码编译和链接原理的更多相关文章
- Linux | GCC如何实现代码编译&&汇编&&链接过程
正文: 每次我们程序员所写的 代码 是给程序员看的呢?还是给电脑看的?其实我们所写的代码只是我们程序员之间交流的一样特殊语言,电脑是看不懂的.那么我们如何实现人机交流呢?这就不得不请出我们我们今天 ...
- C++模板声明与实现分开--由此想到的编译,链接原理
参考了以下两篇文章: C++编译链接原理简介 语言程序编译过程 2 问题来源:当模板文件的实现与声明分开在不同文件中时,链接时会提示找不到相应模板函数,如下 一,编译和链接的大概原理: 1,编译,遍 ...
- 从编译器角度理解C++中的引用和指针
欲分析指针和引用,则要分析变量名和地址之间的关系(不管你理解还是不理解,无论你是从老师那里听到的,还是网上看到的,应该都知道两句话:1. 指针就是地址,2.引用就是给变量起个别名) 所以我们就要来分析 ...
- 多态原理探究-从C++编译器角度理解多态的实现原理
理论知识: 当类中声明虚函数时,编译器会在类中生成一个虚函数表. 虚函数表是一个存储类成员函数指针的数据结构. 虚函数表是由编译器自动生成与维护的. virtual成员函数会被编译器放入虚函数表中. ...
- 小师妹学JVM之:深入理解JIT和编译优化-你看不懂系列
目录 简介 JIT编译器 Tiered Compilation分层编译 OSR(On-Stack Replacement) Deoptimization 常见的编译优化举例 Inlining内联 Br ...
- 如何提升代码编译的速度 iOS
前阵子有遇到代码编译速度慢的问题,特别是在swift和object-c混编的过程中问题很突显. 网上找到一篇蛮好的文章里面又一些解决方法 推荐一下 http://www.open-open.com/l ...
- Linux - Unix环境高级编程(第三版) 代码编译
Unix环境高级编程(第三版) 代码编译 本文地址:http://blog.csdn.net/caroline_wendy 时间:2014.10.2 1. 下载代码:http://www.apuebo ...
- 编译器角度看C++复制构造函数
[C++对象模型]复制构造函数的建构操作 关于复制构造函数的简单介绍,可以看我以前写过的一篇文章C++复制控制之复制构造函数该文章中介绍了复制构造函数的定义.调用时机.也对编译器合成的复制构造函数行为 ...
- 第6章 Python中的动态可执行方法 第6.1节 Python代码编译
在介绍动态可执行方法前,本节先介绍一下Python代码编译有关的知识,因为部分内容和动态执行有些关联. 一. Python解释器的功能 Python虽然是解释型语言,但Python代码也是可编译 ...
随机推荐
- 别梦依稀咒逝川,Ruby二十八年前|M1芯片Mac os系统配置Ruby(3.0.0) on Rails(6.1.1)开发环境(2021最新攻略)
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_188 在每个开发者心里,都会有一门"最好"的语言,在这个世界的某个深处,在一些矫矫不群的人们心中,这门语言的名 ...
- placeholder 设置换行三种方式
在 html 中编写代码时保留代码换行 <textarea name="" id="" cols="30" rows="10 ...
- Linux Shell 自动交互功能
需求背景: 近日,在安装某软件过程,发现在安装过程需要输入一些信息才能继续下一步操作,在机器数量较少情况下,我们可以单台登录上去完成安装操作,但当机器数量超过一定时,如果再手动登录操作,就会产生大 ...
- Apache DolphinScheduler 1.3.6 功能发布说明
参与人员 @chengshiwen.@hailin0.@wanghong1314.@ruanwenjun.@xxjingcd.@zhangguohao.@zhuangchong.@syb8535531 ...
- MySQL通配符与正则表达式
通配符 通配符必须全文匹配时才为真,使用LIKE关键字 字符 示例 含义 _ "a_b" 任意一个字符"axb",其中x可以使任意字符,包括汉字 % " ...
- 急如闪电快如风,彩虹女神跃长空,Go语言高性能Web框架Iris项目实战-初始化项目ep00
在Golang Web编程的世界里,君不言高性能则已,言高性能必称Iris.彩虹女神的名号响彻寰宇.名动江湖,单论一个快字,无人能出其右,就连以简洁轻量著称于世的Gin也难以望其项背,只见彩虹女神Ir ...
- z—libirary最新地址获取,zlibirary地址获取方式,zliabary最新地址,zliabary官网登录方式,zliabary最新登陆
Z-Library(缩写为z-lib,以前称为BookFinder)是Library Genesis的镜像,一个影子图书馆项目,用于对学术期刊文章.学术文本和大众感兴趣的书籍(其中一些是盗版的)进行文 ...
- KingbaseES sys_blocking_pids 函数
会话出现了锁等待,想要快速查询到堵塞的会话,可以使用 sys_blocking_pids 函数来实现这一目的. sys_blocking_pids:获取哪些会话阻塞了某个会话(输入参数). sys_b ...
- KingbaseES R6 集群repmgr.conf参数'recovery'测试案例(一)
KingbaseES R6集群repmgr.conf参数'recovery'测试案例(一) 案例说明: 在KingbaseES R6集群中,主库节点出现宕机(如重启或关机),会产生主备切换,但是当主库 ...
- K8S_删除Pod总结
K8S 不能直接删除Pod,直接删除Pod,会被Deployment重启 删除前,必须先删除对应的Deployment 例子: // 查出Pod [root@k8s-master ~]# kubect ...