C++编译器工作流程

一、编译过程:

第一步,预编译,展开头文件,进行宏替换。

第二步,编译,代码优化(gcc -O1234),符号汇总。

第三步,汇编,根据对应关系,将汇编指令转换为本地操作系统的机器码。

第四步,生成可重定位的目标文件(没有地址),可重定位的目标文件中包含符号表;

二、链接过程:

第一步,将所有的目标文件的段进行合并,其中包括合并符号表,进行符号解析,解析正确,给符号表的符号分配虚拟地址。

第二步,将代码段的指令进行符合重定向。
 

进程在内存上的布局:

C++编译器工作流程_第1张图片

例子:

 

 

两个文件的符号表:


在x86体系32位linux内核/操作系统下:
        每一个进程在运行的时候,系统会为其分配一个以上构造的4G的虚拟地址空间:3G为用户空间(私有)1G为内核空间(共享)对任何一个普通进程,涉及到5种不同段。

代码段:用来存放程序的执行代码,大小在程序运行前已经确定,并且只读不可写,也包含一些只读的常数变量,例字符串常量等。
数据段:用来存放程序中已初始化的全局变量(静态内存分配)。
BSS段:用来存放程序中未初始化的或者初始化为零的全部变量(静态内存分配)。
堆区:用于存放进程运行中被动态分配的内存段,大小不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存,新分配  的内存被动态添加到堆当利用free等函数释放内存时,内存从堆中被剔除。
栈区:用于存放程序临时创建的局部变量,即函数括弧“{}”中定义的变量。函数被调用时,其参数也会被压入发起调用的进程栈中,并且调用结束后,函数返回值也会被存放回栈中。(由操作系统分配,内存的申请和回收都有OS管理)

注意:

           全局的未初始化变量存在于.bss段中,具体表现为一个占位符;
           全局的已初始化变量存在与.data段中;
           函数内的自动变量都在栈上分配空间;
          .bss不占用.exe文件空间,内容由操作系统初始化(清零),.data需要占用,内容由程序初始化;
           bss段:不给该段的数据分配空间,只是记录数据所需空间的大小。
           data段:则数据分配空间,数据保存在目标文件中。

程序的编译,链接,执行过程:

C++编译器工作流程_第2张图片

C++编译器工作流程_第3张图片

1.什么叫可重定位?

重定位就是把程序的逻辑地址空间变换成内存中的实际物理地址空间的过程,也就是说在装入时对目标程序中指令和数据的修改过程。
重定位分为动态重定位和静态重定位。
静态重定位:在程序装入内存的过程中完成,在程序开始运行前,程序中的各个地址有关的项均已完成重定位,地址变换通常是在装入时一次完成的,以后不再改变。
动态重定位:它不是在程序装入内存时完成的,而是CPU每次访问内存时 由动态地址变换机构(硬件)自动进行把相对地址转换为绝对地址。动态重定位需要软件和硬件相互配合完成。

2.为什么.o文件不可执行?

因为.o文件下符号表里的符号未分配地址,所以执行的时候因为找不到存储地址而失败。

1.什么是符号解析?
给未定义的符号,找到其定义的地方。

2.什么是符号重定向?
给符号表的符号分配虚拟地址后,将代码段的符号分配虚拟地址。

3.符号为什么不能直接分配物理内存?
防止物理地址提前分配后,被其它内存占用,以及分配地址冲突,并未知进程运行的时间,产生内存占用。

4.程序运行完成后,物理内存上的地址会释放吗?
动态申请的内存,不会被释放,除非使用free释放函数,否则会造成内存泄漏。但实则系统会自动回收,包括泄露的部分

3. 各个符号的初始化阶段

  const常量是由编译器处理的,提供类型检查和作用域检查

  宏定义由预处理器处理,单纯的文本替换

  typedef发生在编译阶段

 

 

你可能感兴趣的:(编译器工作原理)