509-C++代码的编译和链接原理

C++代码的编译和链接原理

我们在64位的linux Ubuntu系统演示。
我们看下面例子:
在这里插入图片描述
我们看下面示意图
在这里插入图片描述
预编译阶段:

#开头的 都是在预编译阶段处理,进行展开的!!!

但是下面是特例:
#pragma lib的意思是当前程序运行时需要链接的库,必须存活在链接阶段
#pragma link的意思是程序运行以后直接以指定函数为入口函数,也是存活在链接阶段

编译阶段:语法语义词法分析,代码的优化,处理完之后,生成相应平台的汇编代码

汇编阶段: 生成.o可重定位二进制目标文件,也就是把汇编码转成相应平台的机器码
链接阶段:所有.o文件和静态库文件合在一块进行链接。

在这里插入图片描述
链接后,生成可执行文件
gcc -o可以指定程序的名称
在这里插入图片描述

linux示例

在这里插入图片描述
objdump可以查看.o文件和可执行文件的详细信息。
我们查看符号表:
在这里插入图片描述
对应的代码:
在这里插入图片描述
如果当前文件引用外部文件的函数或者全局变量的符号时,在当前main.cpp编译成main.o的文件,这个符号会不会产生呢?

在这里插入图片描述
是会产生符号的,因为不产生符号就使用不了。
符号就是下图中的最右边这一列:
在这里插入图片描述
最左边的UND就是这个符号现在在代码上用到它了,但是却不知道它们是怎么定义的,所以只能给UND,是对符号的引用,不是对符号的定义。
在这里插入图片描述
l是local的意思,在当前文件看得见,g是global的意思,在其他文件也看得见。
链接的时候是所有obj文件在一起链接的,所以对于链接器来说,只能看得见.o文件的g符号,对于l符号链接器看不见。
对于定义静态的全局变量或者静态函数,只能在当前文件可见,其他文件看不见。编译生成的.o文件里面,普通的都是global,静态的都是local。
所以,在多个文件可以定义名字相同的静态全局变量或者静态函数。
但是在多个文件不可以定义名字相同的普通全局变量或者普通函数,符号解析就有冲突了。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
我们看看.o文件的组成:
在这里插入图片描述

在这里插入图片描述
这个文件头我们查看看:
在这里插入图片描述
我们注意:symtab存放的就是符号表

我们查看段:
在这里插入图片描述
我们把各个段都打印出来:

在这里插入图片描述
编译过程中,符号是不分配虚拟地址的(因为都不知道符号在哪里定义的)。
在这里插入图片描述

在这里插入图片描述
我们发现:
在这里插入图片描述
在编译过程中,符号没有分配虚拟地址,但是指令已经分配好了。指令把符号的地址都填充成0,以后改成正确的地址。

链接的步骤

如下图所示:
在这里插入图片描述
在这里插入图片描述
符号解析就是所有对符号的引用都要找到该符号定义的地方。
例如我们前面所述:
在这里插入图片描述
在这里插入图片描述
我们写的代码链接时,可能会报错(符号未定义,符号重定义)
因为符号定义只能在某个.o文件出现1次,但是可以多个地方引用

段的合并,符号表本来就是.o文件的一个段,符号表段在合并的时候,就是符号解析,最终放在可执行文件里,可执行文件就是各种各样的段组成的。

符号解析成功以后:
给所有的符号分配虚拟地址
分配完地址以后,所有符号都有地址了。
然后到代码段上,指令上,原来填的符号地址都是0,现在要重新写上去。
就是符号的重定向!!!
在这里插入图片描述
我们进行链接:
在这里插入图片描述
在这里插入图片描述
所有符号都有其区域的位置和地址了!!!
我们查看代码段:
在这里插入图片描述

在这里插入图片描述
对于sum来说,符号放的是偏移量

符号是在链接过程的第1步:符号解析完成后(对所有符号的引用都要找到其定义的地址),分配虚拟地址。
分配完地址,再跑到代码段的指令上把符号的地址填成符号的正确地址(符号的重定向)

可执行文件的查看

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在文件头记录了当前可执行程序的入口地址:
在这里插入图片描述

在这里插入图片描述

和可重定位目标文件不同的地方,可执行文件多了这么个段:
在这里插入图片描述
在这里插入图片描述
当我们运行可执行文件的时候,系统看program headers
在这里插入图片描述
在这里插入图片描述
程序运行,符号表段,段表内容都不需要往内存上加载,只需要加载的只有代码段和数据段
Align是以页面大小对齐
程序的入口地址:文件头有入口地址。
运行的时候读文件头,从文件头的地址,加载的时候把这个地址加载到CPU的PC寄存器里,加载完成,CPU就从main函数的第一条指令地址开始执行了

可执行文件加载的过程示意图

在这里插入图片描述
详细的过程看我另外一篇博客《Linux内存地址映射》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林林林ZEYU

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值