首页 > 编程语言 ><三>从编译器角度理解C++代码编译和链接原理

<三>从编译器角度理解C++代码编译和链接原理

时间:2022-10-12 09:34:04浏览次数:62  
标签:文件 符号表 符号 int sum 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 就是需要加载到内存中的.


下面我们再看看可执行程序加载到内存过程

标签:文件,符号表,符号,int,sum,C++,编译,编译器,链接
From: https://www.cnblogs.com/erichome/p/16783362.html

相关文章

  • C++智能指针
    C++提供了四个智能指针模版类,分别为:auto_ptr,unique_ptr,shared_ptr与weak_ptr(其中auto_ptr为C++98提供的解决方案,在C++11中已废除,并提供另外三种)。这三者均定义了类似指......
  • c++函数模板
    按照之前所学,是需要根据形参类型的不同来重载函数的。但是根据函数模板则可以解决这个繁琐的问题。调用时才区分类型。 主函数中: 补充: 主函数中:  ......
  • 开源,跨平台免费C++ IDE ---Code::Block
     CodeBlock是一个免费,开源的C++IDE,它看上去有一个一致的外观,满足用户的需要,具有扩展性和可配置性。这个IDE有你需要的所有功能,并且它是跨平台的。另外,其具有插件框架......
  • C++ 智能指针详解
    这篇博客主要参考上面这个博客和《Boost程序库完全开发指南:深入C++准标准库》第三版   一个智能指针就是一个C++的对象,这个对象的行为像一个指针,但是它却可以在其......
  • C++:类、类的构造与析构
    概念引述  C++的OOP特点已经耳熟能详,封装,继承,多态。封装主要体现在namespace、stock、funtion;继承体现为类继承;多态体现为类之间通过继承关联时。因此C++进阶的前提就是......
  • C++ 栈和典型迷宫问题
    1.前言栈是一种受限的数据结构,要求在存储数据时遵循先进后出(LastInFirstOut)的原则。可以把栈看成只有一个口子的桶子,进和出都是走的这个口子(也称为栈顶),封闭的另一端称......
  • c++高级 面试补充
    多线程:多线程分为三个知识点:1.线程的建立,在main中要进行函数终止,  在函数中使用后才能使得main函数在线程结束后才结束。如果不使用,那么可能线程结束前,main函数就结......
  • 用VSCode和CMake编写调试C/C++
    VSCode配置编译任务与调试对象在配置的时候会用到一些vscode的变量,用${}包裹起来的那些。${workspaceFolder}是当前工作空间(或vscode所打开根文件夹)在操作系统中绝对路......
  • 嵌入式linux-busybox 工具静态编译
       嵌入式linux因资源紧缺,所以在制作根文件系统时,使用的是经过裁剪之后的busybox,然而很多工具都没有添加到根文件系统内部(如:traceroute)。假设现在要使用traceroute工......
  • VS2019 使用 C/C++ 动态链接库 并 进行调用
     vs2019生成dll并调用的实现示例:​​https://www.jb51.net/article/179759.htm​​ 1.VS 中生成动态链接库的三种方式(导出函数) 开发环境:VS2019 创建动态链接库项目新......