GCC编译器 & gcc编译过程 ‘ ‘ ‘ ‘ --- 记一次查缺补漏 ‘ ‘

文章目录

  • 前言
  • GCC介绍
  • GCC编译过程
    • 预处理
    • 编译
    • 汇编
    • 链接
      • 关于链接:

前言

学习的过程遇到了.s后缀的文件,原来是gcc的编译过程,复习一下。
又牵扯到了各种C编译器,诸如MSVC、MinGW、Clang+LLVM等,挖个坑先。
还有关于动态链接和静态链接的知识,等等补。

GCC介绍

GCC编译器套装(GNU Compiler Collectin,缩写为GCC)是GNU计划制作的一种优化的编译器,支持各种编程语言、操作系统、计算机系统结构。
该编译器是以GPL及LGPL许可证所发行的自由软件,也是GUN计划的关键部分,还是GNU工具链的主要组成部分之一。 原名为GNU C语言编译器(GNU C Compiler)因为它原本只能处理C语言。如今GCC编译器已经被移植到比其他编译器更多的平台和指令架构上,并被广泛部署在开发自由和专有软件的工具中。
GCC还可以用于许多嵌入式系统,包括ARM和Power ISA的芯片。 GCC不仅是GNU操作系统得官方编译器,还是许多UNIX系统和Linux发行版的标准编译器。

GCC的设计:
GCC的外部接口遵循UNIX使用惯例。用户输入特定语言的驱动程序码(C语言为gcc,C++为g++,如此不一而足)该程序解释命令语句,调用实际编译器,在输出界面上运行汇编器,然后选择性地运行链接器,然后产生一个完整的可执行二进制文件。

GCC的扩展编译流程概览,包括专门的程序如预处理器、汇编器和链接器
GCC编译器 & gcc编译过程 ‘ ‘ ‘ ‘ --- 记一次查缺补漏 ‘ ‘_第1张图片

GCC编译过程

如下图所示,从hello.c到hello(或a.out)文件,必须经历hello.i,hello.s,hello.out,最后才得到hello(或a.out)文件,分别对应着预处理、编译、汇编和链接4个步骤。
在这里插入图片描述
大致工作过程:
1.预处理(Preprocessing)
2.编译(Compilation),
3.汇编(Assemble),
4.链接(Linking)。

准备工作,先写一个C源代码:

#include 

int main() {
    printf("Hello, World!\n");
    return 0;    // 这是一行注释
}

保存为hello.c

预处理

GCC编译的第一阶段是预处理(Preprocessing),在这个阶段,预处理器会对C/C++源代码进行一些操作,部分操作如下:

  • 移除注释
    预处理器会删除源代码中的注释,包括单行注释(//)和多行注释(/* … */).
  • 处理预处理指令
    预处理器会处理源代码中的预处理指令,这些指令以(#)开头,例如 #include、#define、#ifdef、#ifndef 等。其中,#include 指令用于包含头文件,#define 用于宏定义,#ifdef 和 #ifndef 用于条件编译等。
  • 宏展开
    预处理器会展开源代码中的宏,将宏调用替换成宏定义的内容。
  • 生成预处理后的代码文件
    预处理器的最终输出是一个去除了注释,展开了宏等操作的中间代码文件,通常以" .i "扩展名保存。这个文件可以用于接下来的编译步骤。

操作指令:

gcc -E hello.c -o hello.i

-E是预处理指令,-o是生成的文件名称

实际操作如下图:

GCC编译器 & gcc编译过程 ‘ ‘ ‘ ‘ --- 记一次查缺补漏 ‘ ‘_第2张图片

将会得到一个hello.i文件,这是hello.c经过预处理后的文件,用vim打开hello.i观察

GCC编译器 & gcc编译过程 ‘ ‘ ‘ ‘ --- 记一次查缺补漏 ‘ ‘_第3张图片

hello.c文件原来只有6行,经过预处理后增加到了七百多行,多了许多额外的变量、函数等内容,用G跳转到最下面可以发现,源代码部分 注释已经被删除。

GCC编译器 & gcc编译过程 ‘ ‘ ‘ ‘ --- 记一次查缺补漏 ‘ ‘_第4张图片

编译

GCC 编译过程的第二阶段是编译(Compilation)。在这个阶段,编译器将经过预处理的源代码转换成汇编语言代码
在这个阶段,GCC会对经过预处理的源代码进行一些词法语法的分析,生成中间表示(介于源代码和目标代码之间的表达形式),并对源代码进行一定程度的优化,最后GCC将刚刚生成的中间表示转化成目标平台的汇编语言代码。也就是 .s 文件

在gcc编译参数上加-S 可以将hello.i编译成hello.s文件,
指令如下:

gcc -S hello.i

实际操作如下图:

GCC编译器 & gcc编译过程 ‘ ‘ ‘ ‘ --- 记一次查缺补漏 ‘ ‘_第5张图片

hello.s是一个汇编文件,可以用Vim打开查看,如下图

GCC编译器 & gcc编译过程 ‘ ‘ ‘ ‘ --- 记一次查缺补漏 ‘ ‘_第6张图片

汇编

GCC 编译过程的下一个阶段是汇编(Assembly),在这个阶段,编译器将中间表示(通常是汇编语言)转化为目标平台的机器码。

得到.s汇编文件后,就可以用gcc得到机器码了,命令如下:

gcc -c hello.s

实际操作如下:
GCC编译器 & gcc编译过程 ‘ ‘ ‘ ‘ --- 记一次查缺补漏 ‘ ‘_第7张图片
生成了一个hello.o文件,这一步产生的文件叫做目标文件,是二进制格式。

链接

在 GCC 编译过程的链接(Linking)阶段,多个目标文件(通常是编译多个源文件生成的)以及库文件将被合并到一个可执行文件中。链接的主要任务是解析符号引用,将各个目标文件中的代码和数据段组合在一起,解决外部依赖关系,生成最终的可执行文件

命令如下:

gcc hello.o

这样会默认输出a.out文件,也可以用-o指定新的文件名,例如加上 -o hello,这样就会生成hello文件。
如下图:
GCC编译器 & gcc编译过程 ‘ ‘ ‘ ‘ --- 记一次查缺补漏 ‘ ‘_第8张图片
执行一下:
GCC编译器 & gcc编译过程 ‘ ‘ ‘ ‘ --- 记一次查缺补漏 ‘ ‘_第9张图片

关于链接:

链接分为动态链接和静态链接

动态链接使用动态链接库进行链接,生成的程序在执行时需要加载所需的动态库才能运行,动态链接生成的程序小巧,但是必须依赖动态库,否则无法执行。
linux下的动态链接库实际是共享目标文件(shared object),一般是.so文件,作用类似于windows下的.dll文件。
静态链接使用静态库进行链接,生成的程序包含程序运行所需要的全部库,可以直接运行,不过体积较大。
linux下的静态库是汇编产生的.o文件的集合,一般以.a的文件形式出现,gcc默认是动态链接,加上-static参数则采用静态链接,

文献参考

https://www.cnblogs.com/wjchao/p/7460375.html
https://zhuanlan.zhihu.com/p/111500914

你可能感兴趣的:(CTF学习笔记,c语言,GCC,编译器,编译过程,学习)