编译原理之编译过程理解

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

GCC和Clang编译过程理解

前言

GCC:GNU(Gnu’s Not Unix)编译器套装(GNU Compiler Collection,GCC),指一套编程语言编译器,以GPL及LGPL许可证所发行的自由软件,也是GNU项目的关键部分,也是GNU工具链的主要组成部分之一。GCC(特别是其中的C语言编译器)也常被认为是跨平台编译器的事实标准。1985年由理查德·马修·斯托曼开始发展,现在由自由软件基金会负责维护工作。GCC原本用C开发,后来因为LLVM、Clang的崛起,它更快地将开发语言转换为C++。

GCC支持的语言:原名为GNU C语言编译器(GNU C Compiler),因为它原本只能处理C语言。GCC在发布后很快地得到扩展,变得可处理C++。之后也变得可处理Fortran、Pascal、Objective-C、Java、Ada,Go与其他语言。

Clang:是一个C、C++、Objective-C和Objective-C++编程语言的编译器前端。它采用了底层虚拟机(LLVM)作为其后端。它的目标是提供一个GNU编译器套装(GCC)的替代品。作者是克里斯·拉特纳(Chris Lattner),在苹果公司的赞助支持下进行开发,而源代码授权是使用类BSD的伊利诺伊大学厄巴纳-香槟分校开源码许可。Clang主要由C++编写。

Clang项目包括Clang前端和Clang静态分析器等。这个软件项目在2005年由苹果电脑发起,是LLVM(Low Level Virtual Machine)编译器工具集的前端(front-end),目的是输出代码对应的抽象语法树(Abstract Syntax Tree, AST),并将代码编译成LLVM Bitcode。接着在后端(back-end)使用LLVM编译成平台相关的机器语言。
关于gcc与clang的发展历程和性能优异可参考:
https://blog.csdn.net/Poo_Chai/article/details/100266508
https://www.cnblogs.com/findumars/p/14213309.html


环境配置

gcc主要使用win10+VScode
clang使用wsl+vscode+ubuntu16.04
关于在vscode运行wsl:
wsl+vscode+gcc+flex-bison编译原理一条龙_zerolord的博客-CSDN博客_vscode编译原理
https://blog.csdn.net/zerolord/article/details/116379944


GCC

1.单一命令理解编译的过程:

gcc -o main main.c add.c --verbose 也可使用-###选项打印出gcc所执行的各个子命令(gcc -v命令也可以)
verbose详细信息
在这里插入图片描述
Using built-in specs.意思是使用内置的规格,
gcc 是一个驱动式的程序. 它调用其它程序来依次进行编译, 汇编和链接. GCC 分析命令行参数, 然后决定该调用哪一个子程序, 哪些参数应该传递给子程序. 所有这些行为都是由 SPEC 字符串(spec strings)来控制的. 通常情况下, 每一个 GCC 可以调用的子程序都对应着一个 SPEC 字符串, 不过有少数的子程序需要多个 SPEC 字符串来控制他们的行为. 编译到 GCC 中的 SPEC 字符串可以被覆盖, 方法是使用 -specs= 命令行参数来指定一个 SPEC 文件(spec file).
——来源于GCC 编译配置文件 Spec File - 阿呆软件工作室 (adintr.com)
www.adintr.com/mytranslate/gcc_spec_files.html

GCC 已经内置了如下的 SPEC 字符串. SPEC 文件可以覆盖他们或者创建新的. 注意, 某些 GCC 的实现也可能添加它们自己的 SEPC 字符串到这个列表里面.
asm 传递给汇编器的选项
asm_final 传递给汇编后处理器的选项
cpp 传递给 C 预处理器的选项
cc1 传递给 C 编译器的选项
cc1plus 传递给 C++ 编译器的选项
endfile 链接的最后需要包含的目标文件
link 传递给链接器的选项
lib 命令行传递给链接器的要包含的库
libgcc 决定给链接器传递哪个 GCC 支持库
linker 设置链接器的名字
predefines 传递给 C 预处理器的宏定义
signed_char 传递给 CPP 的用于说明 char 默认是否是有符号类型的宏
startfile 一开始就需要传递给链接器的目标文件
COLLECT-GCC与COLLECT_LTO_WRAPPER链接gcc和wrapper的位置
COLLECT_GCC=gcc            //编译时所调用的总调度程序
Target: x86_64-w64-mingw32           //gcc编译得到的可执行文件的运行环境,cpu:64位x86,w64这个类型使用64位兼容方式编译
在这里插入图片描述

Configured with 一些配置的信息
–build=编译该软件所使用的平台
  --host=该软件将运行的平台
  --target=该软件所处理的目标平台
有关配置信息:
configure使用说明_knowledgebao的博客-CSDN博客_configure文件语法
https://blog.csdn.net/knowledgebao/article/details/84657113

在这里插入图片描述
线程模型:posix
具体参考:
mingw-w64线程模型:posix vs win32(posix允许使用c++11的std:: thread,但要带一个winpthreads,可能需要额外dll) - findumars - 博客园 (cnblogs.com)
https://www.cnblogs.com/findumars/p/8290230.html

gcc版本号
COLLECT_GCC_OPTIONS=‘-o’ ‘main.exe’ ‘-v’ ‘-mtune=core2’ '-march=nocona’指定某型号cpu的特殊指令集
在这里插入图片描述

cc1编译器
在这里插入图片描述

包含""所指定的头文件:到程序员自己指定的路径下去搜索
#include “…” search starts here:
包含<>所指定的头文件:到系统指定的路径下去找
#include <…> search starts here:
D:/mingw64/bin/…/lib/gcc/x86_64-w64-mingw32/8.1.0/include
D:/mingw64/bin/…/lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed
D:/mingw64/bin/…/lib/gcc/x86_64-w64-mingw32/8.1.0/…/…/…/…/x86_64-w64-mingw32/include
End of search list.
在这里插入图片描述

as汇编器,生成xxx.s汇编文件是一个临时文件,/tmp目录专门用于存放系统所生成的临时文件,一旦编译得到了可执行文件,这个xxx.s将会被删除
在这里插入图片描述

collect2链接器,由于collect2的路径没有加入环境变量,因此需要我们自己指明collect2所在的路径。
collect2的选项和参数…

关于gcc编译过程还可参考:
剖析gcc -v输出 - 克拉默与矩阵 - 博客园 (cnblogs.com)
https://www.cnblogs.com/kelamoyujuzhen/p/9411002.html

gcc --verbode:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

gcc -###:
在这里插入图片描述

2.多个命令理解编译过程:

gcc -c 命令可把源代码翻译成目标程序,简单来说,先编译成汇编代码,然后经过汇编程序翻译成重定位的目标文件,复杂来说,内部经过了词法分析、语法分析、语义分析、中间代码生成、代码优化、代码生成等生成目标文件。然后在通过 gcc -o 命令把两个目标文件链接成一个可执行程序。

预处理器的主要功能是处理预处理宏(C 语言中以#开头的宏),例如把#include 所包含文件拷贝到 C 文件中,#define 宏展开,#ifdef 根据编译指定选择不同的代码等。
命令:gcc -E 具体命令: gcc -E -o main.i main.c

编译器的主要功能是对源程序进行翻译,输出是汇编语言程序。其翻译主要包含把字符流(文本文件)形成单词流、检查是否满足 C 语言的文法要求、语义转换、代码优化、 目标汇编代码生成等。
命令:gcc -S 具体命令: gcc -S -o main.s main.i

汇编器的主要功能是对汇编源程序进行翻译,目标是可重定位的目标文件。
目标文件不能通过文本编辑器查看,不过可以通过 objdump 命令分析它的内容。
命令:gcc -c 或者 as gcc -c -o main.o main.s
可重定位程序包含了很多 Section,主要包含.text、.data、.bss 等,.text 保存的是 CPU 指令,.data 保存的是初始化的全局变量或者静态变量,.bss 保存的是未初始化的全局变 量或者静态变量。

链接器的主要功能是把多个可重定位目标文件或者动态库或静态库进行符号地址值确定、多个目标文件合并成可执行程序。 命令:gcc 或者 ld 命令执行链接,若静态链接则需指定-static gcc -o main main.o add.o
在这里插入图片描述
Objdump -f main.o 文件头信息
PE格式(windows10):
在这里插入图片描述

ELF格式(ubuntu16.04):

在这里插入图片描述RELOC重定位
Start address 程序开始的地址

objdump -x main.o 可查看目标文件中的 Section
由于我用的是windows系统,所以文件格式是PE格式
关于PE格式详解可参考:
PE格式_百度百科 (baidu.com)
https://baike.baidu.com/item/PE格式/9812617

关于Linux系统使用的ELF文件格式可参考:
目标文件和ELF格式详解 - 简书 (jianshu.com)
https://www.jianshu.com/p/132412ca73ce

在这里插入图片描述
objdump -d main.o 可查看目标文件中代码段的反汇编信息
请注意下面的 callq 24 <main+0x24>以及 mov 0x0(%rip),%edx 指令中包含有四字节的 0,这主要是因为这些位置未定,需要在链接时重定位。
在这里插入图片描述

Clang

第一步:分析预处理功能
命令:clang -E test.c
第二步:分析词法功能
命令:clang -fsyntax-only -Xclang -dump-tokens test.c

第三步:分析语法产生出的抽象语法树 命令:clang -fsyntax-only -Xclang -ast-dump test.c
第四步:中间代码生成,test.ll 可查看,分析中间 IR 与源程序的对应关系 命令:clang -S -emit-llvm -o test.ll test.c
第五步:汇编语言生成 命令:llc test.ll -o test.s
第六步:可执行程序生成 命令:clang test.s -o test
第七步:反汇编 test 程序,分析目标程序与中间 IR 的对应关系 命令:objdump -dS test 命令:clang -g -o test test.c 后通过 objdump 查看反汇编更合适

在这里插入图片描述

在这里插入图片描述
关于clang和llvm在编译过程中的具体细节不再赘述,了解过程。


总结

了解编译过程,可以为学习编译器搭建打基础。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值