zoukankan      html  css  js  c++  java
  • C/C++源程序到可执行程序exe的全过程(及汇编和反汇编的区别)

    一个现代编译器的主要工作流程如下:

    源程序(source code)→预处理器(preprocessor)→编译器(compiler)→汇编程序(assembler)→目标程序(object code)→连接器(链接器,Linker)→可执行程序(executables)。

    简言之,源文件生成可执行文件的过程总共是经历了预编译/预处理,编译,汇编,链接这四个过程。

    如下图所示:

    下面用源文件test.c进行解释,test.c中代码为:

    #include <stdio.h>
    int main()
    {
           printf("hello world!
    ");
           return 0;
    }

    如输入命令:gcc test.c 

    则会完成上述四个过程,直接默认生成可执行文件a.out

    如下图所示:

    gcc参数如下:

    下面分别对上述四个过程进行说明。

    1.预编译/预处理——生成test.i

    命令:gcc -E test.c > test.i  或  gcc -E test.c -o test.i

    注:只有预编译/预处理可以>重定向,因为 gcc -E test.c的结果会在终端显示而不生成文件。

    其实预编译就是我们所说的预处理。 

    预编译/预处理主要作用:

    处理关于 “#” 的指令

    【1】删除#define,展开所有宏定义。例#define portnumber 8080

    【2】处理条件预编译 #if, #ifdef, #if, #elif,#endif

    【3】处理“#include”预编译指令,将包含的“.h”文件插入对应位置。这可是递归进行的,文件内可能包含其他“.h”文件。

    【4】删除所有注释。/**/,//。

    【5】添加行号和文件标识符。用于显示调试信息:错误或警告的位置。

    【6】保留#pragma编译器指令。(1)设定编译器状态,(2)指示编译器完成一些特定的动作。

    在四个过程中,第一个进行的是预编译的过程。 

    接下来,我们一步步详细讨论下其中发生的:

    第一步发生的是预编译,在这我们使用-E指令,使用这个指令会使程序只进行到预编译指令。把预编译的结果放到test.i文件中。在预编译的过程中,主要处理源代码中的预处理指令,引入头文件,去除注释,处理所有的条件编译指令,宏的替换,添加行号,保留所有的编译器指令。

    下图就是预编译后得到的结果 。

    所以当进行预编译以后的文件中将不再存在宏,所有的宏都已经被替代。当我们想要判断宏是否正确或者头文件包含是否正确的时候,我们也可以通过预编译来查看。

    2.编译——生成汇编代码文件test.s

    命令:gcc -S test.c -o test.s 或 gcc -S test.i -o test.s

    注:gcc -S test.c 或 gcc -S test.i 会默认生成test.s文件。

    在预处理结束后,我们所要进行的就是编译。编译过程所进行的是对预处理后的文件进行语法分析,词法分析,语义分析,符号汇总,然后生成汇编代码文件test.s

    test.s打开以后的结果是:

    从结果我们可以知道,得到的是汇编代码。

    3.汇编——生成二进制目标文件test.o

    命令:gcc -c test.c -o test.o 或 gcc -c test.s -o test.o  gcc -c test.i -o test.o

    注1:gcc -c test.c 或 gcc -c test.s 或 gcc -c test.i 会默认生成test.o文件。

    注2:gcc -c x1.c x2.c  结果将生成:两个目标文件x1.o  x2.o

    这里的汇编所说的是一个过程,将汇编代码转成二进制文件,二进制文件就可以让机器来读取。每一条汇编语句都会产生一句机器语言。相当于windows下的.obj文件。这里生成的目标文件里面就是二进制文件。另外,在这需要注意的是,会形成符号表,给这些符号会分配虚拟地址。

    4.链接——生成默认a.out

    命令:gcc test1.c test2.c -o test 或 gcc test1.o test2.o -o test

    链接,其实就是将二进制文件链接成为一个可执行的指令。 

    链接所完成的任务是合并段表,然后把符号表合并并且对符号表进行重定位。

    所谓合并段表,源代码编译生成的a.out会包含很多段,数据段文本段bss段等等,这些段是合并出来的,在编译过程中划分出来的,不同的数据会对应到不同的段中,在.o文件中其实已经发生了分段。

    符号表合并和重定位说的是最后只生成了一个符号表,这个符号表是由前面汇编形成的多个符号表进行合并。在这里不在同一个符号表的符号,要对他们进行重定位。

    补充1:Microsoft Visual Studio中的源代码到可执行程序exe如下图所示:

    图中“编译器”(相当于VS中的编译Ctrl+F7),其实包含了预处理,编译,汇编三个过程。

    Microsoft Visual Studio中的编译(Ctrl+F7)相当于前述预处理,编译,汇编三个过程,将生成obj目标文件。但不会生成exe文件。

    我想这也是大部分人将“编译”理解为生成obj文件的原因。其实汇编才是生成obj文件,编译是生成汇编代码文件。

    补充2:汇编和反汇编的区别

    汇编是将汇编语言翻译成机器语言的过程。 也就是test.s文件经过汇编器变成二进制目标文件test.o文件的过程。

    反汇编指的是由已生成的机器语言(二进制语言)转化为汇编语言的过程,也就是汇编的逆向过程。

    在Linux下利用反汇编器对.o文件进行反汇编。 如下图所示。
    命令: objdump -d test.o  

    可看出和test.s中内容几乎一样!

  • 相关阅读:
    How to Create a site at the specified URL and new database (CommandLine Operation)
    Using Wppackager to Package and Deploy Web Parts for Microsoft SharePoint Products and Technologies
    SQL Server Monitor v0.5 [Free tool]
    How to build Web Part
    Deploy web part in a virtual server by developing a Web Part Package file(.cab)
    How to recreate "sites" link if you delete it accidentally
    SharePoint Portal Server管理匿名访问设置
    Monitor sql connection from .Net SqlClient Data Provider
    Brief installation instruction of Sharepoint Portal Server
    How to Use SharePoint Alternate URL Access
  • 原文地址:https://www.cnblogs.com/a3192048/p/12241248.html
Copyright © 2011-2022 走看看