0
点赞
收藏
分享

微信扫一扫

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

勇敢的趙迦禾 2022-05-05 阅读 183

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

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

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

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

编译阶段:语法语义词法分析,代码的优化;处理完之后,生成相应平台的汇编代码(gcc/g++ 后面加参数 )

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

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

在这里插入图片描述
在这里插入图片描述

linux举例分析

1、编译过程

在这里插入图片描述

objdump可以查看.o文件和可执行文件的详细信息。

我们查看符号表:
在这里插入图片描述
如果当前文件引用外部文件的函数或者全局变量的符号时,在当前main.cpp编译成main.o的文件,这个符号会不会产生呢?
在这里插入图片描述
是会产生符号的,因为不产生符号就使用不了。

符号就是下图中的最右边这一列:
在这里插入图片描述

main函数和全局变量data分别放在.text段和.data段!
在这里插入图片描述
在这里插入图片描述
最左边的UND就是这个符号现在在代码上用到它了,但是却不知道它们是怎么定义的,所以只能给UND,是对符号的引用,不是对符号的定义。
在这里插入图片描述

  • l是local的意思,在当前文件看得见,g是global的意思,在其他文件也看得见。
  • 链接的时候是所有obj文件在一起链接的,所以对于链接器来说,只能看得见.o文件的g符号,对于l符号链接器看不见。
  • 对于定义静态的全局变量或者静态函数,只能在当前文件可见,其他文件看不见。
  • 编译生成的.o文件里面,普通的都是global,静态的都是local。
  • 所以,在多个文件可以定义名字相同的静态全局变量或者静态函数
  • 但是在多个文件不可以定义名字相同的普通全局变量或者普通函数,符号解析就有冲突了。

在这里插入图片描述
在这里插入图片描述
可以看到sum函数和gdata变量都已经定义出来了。

main函数:
在这里插入图片描述
sum函数:
在这里插入图片描述
符号表就是汇编器在将汇编码转成最终的.o文件的时候,会给文件生成符号表,不仅会生成符号表,还会生成各种段!
在这里插入图片描述
在这里插入图片描述

这个文件头我们查看看:
在这里插入图片描述
不是一个可执行的文件,是一个可重定位的文件。

注意:symtab存放的就是符号表

将常见的段都打印出来:
在这里插入图片描述
将所有的段都打印出来:
在这里插入图片描述
编译过程中,符号是不分配虚拟地址的(因为都不知道符号在哪里定义的)。是在链接的时候分配地址的
在这里插入图片描述
在这里插入图片描述
上面看不出来信息,我们需要在编译的时候加上调试信息:
在这里插入图片描述
在按上面的objdump -S main.o打开:
在这里插入图片描述
再查看sum.o文件:
在这里插入图片描述
我们看mian函数:
在这里插入图片描述

  • 在编译过程中,符号没有分配虚拟地址,但是指令已经分配好了。
  • 因为符号的地址不确定,所以将在指令上,将符号的地址都填充为0。
  • 后面再将这些符号的地址改成正确的地址。

编译过程重要的部分:

  • 符号表
  • 最终生成的.o文件都放了哪些东西

2、链接过程

所有的.o文件都长一样,各种段:
在这里插入图片描述

链接第1步:段的合并

在这里插入图片描述

main.o,sum.o在链接合并的时候,各个段全部进行合并:
在这里插入图片描述
在这里插入图片描述

所有.o文件段合并之后,就到了符号表的合并,进行符号解析;

  • 符号解析就是所有对符号的引用都要找到该符号定义的地方;
  • 就是* UND *找到其到底是在data段还是在text段;
  • 比如main.o文件中sum函数和gdata都是UND的,要在其他.O文件中的符号表中找一下,没找到的话,链接器就会报错;若果找到多个文件都有定义,链接器也会进行报错。(因为符号定义只能在某个.o文件出现1次,但是可以多个地方引用
  • 可能会报错(符号未定义,符号重定义)

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

链接第2步:符号重定向

符号解析成功以后:(所有对符号引用的都找到了符号定义的地方)

  • 给所有的符号分配虚拟地址
  • 分配完地址以后,所有符号都有地址了。
  • 然后到代码段上,指令上,原来填的符号地址都是0,现在要重新写上去。
  • 就是符号的重定向!!!

在这里插入图片描述
我们自己进行链接:

使用-e 指定入库函数:
在这里插入图片描述
在这里插入图片描述
所有符号都有其区域的位置和地址了!

我们查看代码段:
在这里插入图片描述
可以看到符号都有地址了:
在这里插入图片描述
对于sum来说,符号放的是偏移量

3、可执行文件

举报

相关推荐

0 条评论