[置顶] 编译背后的秘密

我们在控制台打印hello过程究竟发生了什么事,然我们一起目睹

你们知道我们最平时写的最简单的程序hello都干了什么了吗下面让我们一起来看一下

图:编译过程


程序:

#include <iostream>

using namespace std;

#define pi 3.14

int main()

{

        //see helloword in screen

        cout<<"helloword"<<endl;

        cout<<"pi"<<pi<<endl;

        return 0;

}


 

1、预编译

我们首先连做下预编译操作看看生成了什么?

g++ -E hello.cpp -o hello.ii


这个小小的预编译过程看我们预编译生成的文件变成了这么多行的一个文件,这个过程其实就是把#开始的预编译命令#define #include等操作

a、将#define xx  xx中的内容替换到我们预编译文件中

b、条件预编译指令#if #ifdef #ifndef #elseif # else #endif

c、#include 将我们要引入的文件直接粘贴在我们#include的地方

d、删除注释 //  /**/

e、添加行号和文件标识符 #2 hello.cpp 用于调试时定位位置信息

f、保留#pragma指令

1、编译

这部操作把预处理文件进行一系类的词法分析语法分析语义分析级优化后产生相应的汇编代码。

g++ -s hello.ii -o hello.s

这样就可以生成hello.s汇编文件

上面操作:扫描 语法分析 语义分析 源代码优化 代码生成 目标代码优化

a、词法分析:理由难过一个中类似有限状态机将源代码分割为记号,放入符号表

b、语法分析:产生语法树,(采用了上下文无关语法),通过语法树分析语法错误比如括号不匹配等问题

c、语义分析:静态语义、动态语义(识别了变量类型啊,赋值是否匹配啊,除数为0啊都可以识别出来)

d、源码级优化:一些初期可以优化的地方比如常量计算、比如a = 1 + 2 c = b +a 优化后就变为c= b+3

e、目标代码生成优化:选择合适的寻址方式、使用移位来实现乘法计算,删除多余指令

1、汇编

这个过程是将刚才我们生成的汇编代码编译为机器可以执行的指令。

g++ -c hello.S -o hello.o

2、链接

链接过程不看不知道一看吓一跳 怎么这么大一堆连接内容我 看着有点恐怖 后面慢慢分析

链接的个过程主要包括了地址和空间分配、符号决议和重定位(重定位:地址修正)(感觉最主要做的就是将函数信息地址等进行重定位,让程序在运行的时候可以找到其它模块中的函数活变量的地址

ld -static /usr/lib/gcc/i386-redhat-linux/3.4.5/../../../crt1.o /usr/lib/gcc/i386-redhat-linux/3.4.5/../../../crti.o /usr/lib/gcc/i386-redhat-linux/3.4.5/crtbegin.o -L/usr/lib/gcc/i386-redhat-linux/3.4.5 -L/usr/lib/gcc/i386-redhat-linux/3.4.5 -L/usr/lib/gcc/i386-redhat-linux/3.4.5/../../.. /tmp/ccEoWbUY.o helloword.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/i386-redhat-linux/3.4.5/crtend.o /usr/lib/gcc/i386-redhat-linux/3.4.5/../../../crtn.o

3、我们来看看用g++ -c hello.cpp -o hello.o -v(编译)和g++hello.cpp -o hello.o -v(生成可执行程序)执行过程中都干了什么可以很清晰看到


 

原文地址:https://www.cnblogs.com/riasky/p/3483536.html