GCC编译过程分解

10 篇文章 0 订阅
订阅专栏

GCC 原名为 GNU C 语言编译器(GNU C Compiler),因为它原本只能处理 C语言。GCC 很快地扩展,变得可处理 C++。后来又扩展能够支持更多编程语言,如Fortran、Pascal、Objective-C、Java、Ada、Go以及各类处理器架构上的汇编语言等,所以改名GNU编译器套件(GNU Compiler Collection)。

编译器的工作是将源代码(通常使用高级语言编写)翻译成目标代码(通常是低级的目标代码或者机器语言),在现代编译器的实现中,这个工作一般是分为两个阶段来实现:

  1. 编译器的前端接受输入的源代码,经过词法、语法和语义分析等等得到源程序的某种中间表示方式。
  2. 编译器的后端将前端处理生成的中间表示方式进行一些优化,并最终生成在目标机器上可运行的代码。

GCC 设计中有两个重要的目标:

  • 硬件无关性:在构建支持不同硬件平台的编译器时,它的代码能够最大程度的被复用。
  • 要生成高质量的可执行代码,这就需要对代码进行集中的优化。

为了实现这两个目标,GCC 内部使用了一种硬件平台无关的语言,它能对实际的体系结构做一种抽象,这个中间语言为 RTL(Register Transfer Language)。

GCC的编译过程

GCC的编译过程可以分为以下四个阶段:预处理(或预编译)、编译、汇编、链接,如下图所示:

以下面代码为例:

int main()

    printf("Hello World\n");

    return 0;

}

include两种方式:

#include<> 引用的是编译器的类库路径里面的头文件。

#include” “ 引用的是程序目录的相对路径中的头文件。

gcc命令只是后台程序的包装,它会根据不同的参数要求去调用预编译编译程序cc1、汇编器as、链接器ld。

预编译

# gcc –E test.c –o test.i
或者
# cpp -o test.i test.c

以下为test.i部分内容:

# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "test.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 27 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/features.h" 1 3 4
…………
# 2 "test.c" 2
int main()

{    

    printf("Hello World"\n);

    return 0;

}    

将所有的#define删除,并且展开所有的宏定义;预处理过程主要处理那些源代码中以#开始的预处理指令,主要处理规则如下:

  • 处理所有条件编译指令,如#if,#ifdef等;
  • 处理#include预处理指令,将被包含的文件插入到该预处理指令的位置。该过程递归进行,及被包含的文件可能还包含其他文件。
  • 删除所有的注释//和 /**/;
  • 添加行号和文件标识,如#2 “hello.c” 2,以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号信息;
  • 保留所有的#pragma编译器指令,因为编译器须要使用它们;

经过预编译后的.i文件不包含任何宏定义,因为所有的宏都已经被展开,并且包含的文件也已经被插入到.i文件中。所以当无法判断宏定义是否正确或头文件包含是否正确使,可以查看预编译后的文件来确定问题。

编译

编译过程就是把预处理完的文件进行一系列词法分析、语法分析、语义分析及优化后生成相应的汇编代码文件。这个过程是整个程序构建的核心部分,也是最复杂的部分之一。

# gcc -S test.i -o test.s
或者
# ccl -o test.s test.i

以下为test.s部分内容:

.file "test.c"
.section .rodata
.LC0:
.string "Hello World"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $.LC0, %edi
call puts
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-16)"
.section .note.GNU-stack,"",@progbits

汇编

汇编器是将汇编代码转变成机器可以执行的命令,每一个汇编语句几乎都对应一条机器指令。汇编相对于编译过程比较简单,根据汇编指令和机器指令的对照表一一翻译即可。

# gcc -c test.c -o test.o
或者
# as -o test.o test.s

test.o的内容为机器码,不能以文本形式方便的呈现(不过可以利用 objdump -S file 查看源码反汇编)。利用hexdump 查看如下:

# hexdump test.o
0000000 457f 464c 0102 0001 0000 0000 0000 0000
0000010 0001 003e 0001 0000 0000 0000 0000 0000
0000020 0000 0000 0000 0000 0298 0000 0000 0000
0000030 0000 0000 0040 0000 0000 0040 000d 000a
0000040 4855 e589 00bf 0000 e800 0000 0000 00b8
0000050 0000 5d00 48c3 6c65 6f6c 5720 726f 646c
0000060 0000 4347 3a43 2820 4e47 2955 3420 382e
0000070 352e 3220 3130 3035 3236 2033 5228 6465
0000080 4820 7461 3420 382e 352e 312d 2936 0000
0000090 0014 0000 0000 0000 7a01 0052 7801 0110
00000a0 0c1b 0807 0190 0000 001c 0000 001c 0000
00000b0 0000 0000 0015 0000 4100 100e 0286 0d43
00000c0 5006 070c 0008 0000 2e00 7973 746d 6261
00000d0 2e00 7473 7472 6261 2e00 6873 7473 7472
00000e0 6261 2e00 6572 616c 742e 7865 0074 642e
00000f0 7461 0061 622e 7373 2e00 6f72 6164 6174
0000100 2e00 6f63 6d6d 6e65 0074 6e2e 746f 2e65
0000110 4e47 2d55 7473 6361 006b 722e 6c65 2e61
0000120 6865 665f 6172 656d 0000 0000 0000 0000
0000130 0000 0000 0000 0000 0000 0000 0000 0000

链接

链接器ld将各个目标文件组装在一起,解决符号依赖,库依赖关系,并生成可执行文件。如下形式:

ld –static crt1.o crti.o crtbeginT.o test.o –start-group –lgcc –lgcc_eh –lc-end-group crtend.o crtn.o (省略了文件的路径名)

# gcc -o test test.o或者# ld -o test test.o


test程序调用了printf 函数,这个函数是标准C库中的一个函数,它保存在一个名为printf.o 的文件中,这个文件必须以某种方式合并到test.o的程序中。

链接器ld负责处理这种合并。结果得到test可执行文件,可以被加载到内存中由系统执行。

小结

以上过程可以参考下图:

转载于:http://chengqian90.com/2017/C%E8%AF%AD%E8%A8%80/GCC%E7%BC%96%E8%AF%91%E8%BF%87%E7%A8%8B%E8%AF%A6%E8%A7%A3/

浅谈关于c++中的优化
WangXinyu_090926的博客
11-28 1205
快读快写
#pragma GCC poison 的一个有趣特性
zgw071415的专栏
04-11 2514
今天做程序设计的作业时又看见一题,让使用char*实现一个"String"类(与std::string相似),但是要求上传的String类的.cpp实现代码却没有禁用string,导致一些函数直接可以先转换为string对象,用string提供的函数实现以后再转换回char*……然后就想应该可以用#pragma GCC poison来实现禁用string,但是同时也想到,
【C语言进阶剖析】24、#pragma 使用分析
桑凯旋的博客
11-25 2216
今天学习一个非常的预处理指示字 #pragma,在实际工程开发中这个预处理指示字用的非常多,我们以前却接触的非常少,为什么呢,因为 #pragma 是 C 语言留给编译器生产厂商对 C 语言进行扩展了一个特殊的预处理指示字。这也就导致了一个问题,#pragma 在不同的编译器之间可能是语法移植的,这里我们学习几个常用的功能。 1 #pragma 简介 #pragma 用于指示编译器完成一些特定...
c++优化程序(上)
最新发布
weixin_72829799的博客
12-24 179
c++程序速度超级优化!
Pragma section
mirandali的专栏
06-18 9349
设置对象section的另一种方法是使用 pragma section。 通过使用编译指示section,可以通过为整组对象设置编译指示section,轻松地将多个对象定位到用户定义的section中。 该组必须包含在 pragma section 指令中才能正确设置该section和该section的属性: #pragma section "<name>" [<flags>] [<alignment>]<objects>#pragma section &
gcc源码总结
02-27
gcc编译器在编译源代码时,首先将源代码解析成语法树,然后对语法树进行操作,以生成机器代码。语法树的操作包括语法树的构建、遍历和修改等。 2. 程序解析: 程序解析是gcc编译器中的一种重要步骤,用于将源代码...
C/C++程序编译流程详解
09-02
预处理后的代码文件进入编译阶段,由编译器(如GCC的cc1或clang的cc1plus)进行处理。编译器首先进行词法分析,将源代码分解成一个个的记号(tokens)。接着是语法分析,将记号组合成抽象语法树(AST),确保代码...
AVR_GCC程序设计基础
08-03
它负责编译过程的自动化,一般情况下,如果选择默认设置,则无需在选项中勾选"use external makefile"。若需自定义Makefile,将其放在工程目录下,并根据实际需求修改MFile中的参数,如"PROJECT"(项目名称)、"MCU...
gcc开始 实例引导
10-23
GCC,全称GNU Compiler Collection,是GNU项目的一部分...预编译编译和链接的分解理解有助于我们深入理解程序从源代码到可执行文件的转化过程。在实际项目中,理解这些基本概念将使我们能够更有效地调试和优化代码。
makefile详解(自己在网上找的)
09-01
编译阶段,源代码(如C/C++的`.c`或`.cpp`文件)被编译器(如GCC或CC)转化为目标文件(`.o`文件),这个过程只检查语法和函数声明。如果函数未声明,编译器会发出警告,但仍然可以生成目标文件。链接阶段,所有目标...
编译原理(第2版)课件
03-28
13.4.2 GCC编译程序的安装与配置 13.5 GCC的优化 13.5.1 概述 13.5.2 窥孔优化 13.5.3 基于机器描述的窥孔优化 13.5.4 修改GCC源程序的窥孔优化 练习 第14章 面向对象语言的编译 14.1 面向对象语言的基本概念 14.2 ...
实例详解Linux下的Make命令
01-10
而且如此多的源文件,如果每次都要键入gcc命令进行编译的话,那对程序员 来说简直就是一场灾难。而make工具则可自动完成编译工作,并且可以只对程序员在上次编译后修改过的部分进行编译。因此,有效的利用make和 ...
The compiler design handbook optimizations and machine code gen
01-13
机器码生成是编译过程的最后阶段,涉及将中间代码转换为目标机器的指令集。这一过程通常需要考虑目标架构的特性,比如指令集架构(ISA)、寻址模式、寄存器使用策略等。优化的机器码生成不仅要确保正确性,还要尽...
一种解析GCC抽象语法树的方法_石峰1
08-03
GCC(GNU Compiler Collection)是一个由美国自由软件基金会开发的开源编译器系统,它能够编译多种编程语言,并且在多个平台上运行。GCC的架构分为前端、后端和机器描述三个部分。在GCC中,抽象语法树(AST,...
课程论文-LU分解的OpenMP实现.docx
11-20
在实验平台上,选用的是Debian GNU/Linux操作系统,搭配GCC 4.3编译环境。实验要求学生理解并行算法的基本原理,同时探索算法的改进和优化方法。例如,在实现LU分解时,可以通过预处理减少浮点运算次数,或者利用...
#pragma的详细用法
Gick
08-28 2961
转载自:https://www.cnblogs.com/azraelly/archive/2012/07/05/2577334.html 每种C和C++的实现支持对其宿主机或操作系统唯一的功能。例如,一些程序需要精确控制超出数据所在的储存 空间,或着控制特定函数接受参数的方式。#pragma指示使每个编译程序在保留C和C++语言的整体兼容性时提 供不同机器和操作系统特定的功能。编译指示被定义为机...
gcc pragma
alloc_young的专栏
06-09 2408
#pragma GCC dependency#pragma GCC dependency allows you to check the relative dates of the current file and another file. If the other file is more recent than the current file, a warning is issued. T
GCC编译的四个过程
Jocheng的博客
04-27 1181
GCC编译的四个过程分别为:预处理->编译->汇编->链接 1、预处理阶段:使用 gcc -E hello.c -o hello.i   预处理阶段完毕之后就停止编译。hello.i就是预处理之后的的文件 其中预处理过程主要是对要编译的c文件的头文件做一个处理,将#开头的头文件内容告诉处理器。 2、编译阶段:gcc -S hello.i -o hello.s  只进行编译这个阶段之后结束编译
gcc编译器工作原理
10-12
gcc编译器的工作原理可以分为四个阶段:预处理、编译、汇编和链接。 1. 预处理阶段:在这个阶段,gcc会对源代码进行预处理,主要包括以下几个步骤: - 处理头文件:将#include指令所包含的头文件内容插入到源代码...

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
写文章

热门文章

  • ceph-deploy osd 出错 10007
  • ceph HEALTH_WARN no active mgr 8344
  • kubernetes的eviction机制 8335
  • Ceph RGW 设计与实现 7832
  • 使用awk命令获取文本的某一行,某一列 7343

分类专栏

  • 算法 4篇
  • 数据库 4篇
  • 服务器构架 8篇
  • linux 10篇
  • C++ 11篇
  • lua
  • ceph 13篇
  • 网络 3篇
  • git
  • Qos 1篇
  • golang 11篇
  • 分布式 1篇
  • k8s 13篇
  • docker 2篇
  • shell 1篇
  • Python
  • nosql 3篇
  • 亲和性 1篇
  • 反亲和性 1篇
  • etcd 1篇

最新评论

  • Ceph RGW 对象上传源码分析

    下一页盛夏花开: 谢谢博主,学习了

  • kubernetes调度实践及原理分析

    info_H: 写得很详细,谢谢博主

  • Ceph RGW 设计与实现

    大锤爱编程: 写的真好 非常详细

  • 浅谈服务治理与微服务

    LongLongRiver: 微服务治理是微服务架构可持续深入演进的基石,如果想深入了解微服务治理,可以参考电子工业出版社新推出的书籍:《微服务治理:体系、架构及实践》,400多页的书籍,道尽微服务治理的方方面面。

  • C++ emplace_back 和 push_back 的区别

    funnytiger123: 楼主你这个颜色根本看不清啊

大家在看

  • Java计算机毕业设计基于Android的高校学生体育素质分析挖掘与应用(开题报告+源码+论文)
  • 分散聚集 IO
  • 基于springboot实现计算机学院校友网管理系统项目【项目源码+论文说明】计算机毕业设计
  • 810、基于51单片机的温度测量(存储,查询,数码管) 145
  • 2024国内外音频转换器大盘点,盘点音乐剪辑的7个有效方法!

最新文章

  • 浅谈系统线程数限制
  • 详解 Kubernetes ReplicaSet 的实现原理
  • 替换字符串中的通配符
2019年11篇
2018年54篇
2017年23篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值

哆哆女性网咨询公司起名大全参照英雄枪战任务栏怎么还原到下面西游记红孩儿起名字姓谷女孩星座起名网特朗普所乘专机险撞机忍者杀手p2p网贷平台排名赵薇女儿家庭贴膜方姓女孩起名子红舵码头父母起名起名重生之绝色风流炎黄盛世绳艺美女孩子起名周什么好呢女宝宝起名缺水木失婚属鼠的人起名字吗正青春在线全集免费观看完整版吴贤起名噤若寒蝉的意思李字起个名字先进集体事迹材料起名字诗意的男孩公司起名查凶猛明月珰六宫粉免费宝宝起名中间字固定淀粉肠小王子日销售额涨超10倍罗斯否认插足凯特王妃婚姻不负春光新的一天从800个哈欠开始有个姐真把千机伞做出来了国产伟哥去年销售近13亿充个话费竟沦为间接洗钱工具重庆警方辟谣“男子杀人焚尸”男子给前妻转账 现任妻子起诉要回春分繁花正当时呼北高速交通事故已致14人死亡杨洋拄拐现身医院月嫂回应掌掴婴儿是在赶虫子男孩疑遭霸凌 家长讨说法被踢出群因自嘲式简历走红的教授更新简介网友建议重庆地铁不准乘客携带菜筐清明节放假3天调休1天郑州一火锅店爆改成麻辣烫店19岁小伙救下5人后溺亡 多方发声两大学生合买彩票中奖一人不认账张家界的山上“长”满了韩国人?单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#青海通报栏杆断裂小学生跌落住进ICU代拍被何赛飞拿着魔杖追着打315晚会后胖东来又人满为患了当地回应沈阳致3死车祸车主疑毒驾武汉大学樱花即将进入盛花期张立群任西安交通大学校长为江西彩礼“减负”的“试婚人”网友洛杉矶偶遇贾玲倪萍分享减重40斤方法男孩8年未见母亲被告知被遗忘小米汽车超级工厂正式揭幕周杰伦一审败诉网易特朗普谈“凯特王妃P图照”考生莫言也上北大硕士复试名单了妈妈回应孩子在校撞护栏坠楼恒大被罚41.75亿到底怎么缴男子持台球杆殴打2名女店员被抓校方回应护栏损坏小学生课间坠楼外国人感慨凌晨的中国很安全火箭最近9战8胜1负王树国3次鞠躬告别西交大师生房客欠租失踪 房东直发愁萧美琴窜访捷克 外交部回应山西省委原副书记商黎光被逮捕阿根廷将发行1万与2万面值的纸币英国王室又一合照被质疑P图男子被猫抓伤后确诊“猫抓病”

哆哆女性网 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化