gcc编译器的工作流程
参考资料:http://www.cnblogs.com/dfcao/p/csapp_intr1_1-2.html
在linux系统上,从源文件到目标文件的转化是由编译器完成的。以hello.c程序的编译为例,如下:
dfcao@linux: gcc -o hello hello.c
在这里,gcc编译器读取源文件hello.c,并把它翻译成一个可执行文件 hello。
这个翻译过程可分为四个阶段逐步完成:预处理,编译,汇编,链接,如下图所示。

逐步做下简单分析:
在未编译前,hello.c 的源代码如下
#include <stdio.h> int main()
{
printf("hello, world\n");
}
第一步、预处理阶段
执行命令: gcc -o hello.i -E hello.c
或者 cpp -o hello.i hello.c (这里cpp不是值c plus plus,而是预处理器the C Preprocessor)
预处理器cpp根据以字符开头#开头的命令,修改原始C程序。比如hello.c中的第一行为 #include <stdio.h>,预处理器便将stdio.h的内容直接插入到程序中。
预处理之后得到文本文件hello.i,打开如下

# 1 "hello.c"
# 1 "<built-in>"
# 1 "<命令行>"
# 1 "hello.c"
# 1 "/usr/include/stdio.h" 1 3 4
...
...
...
extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
# 940 "/usr/include/stdio.h" 3 4 # 2 "hello.c" 2 int main()
{
printf("hello, world\n");
}

在源代码的前面插入了stdio.h,整个hello.i 的行数由hello.c的6行变到了855行!
第二步、编译阶段
执行命令: gcc -o hello.s -S hello.i
或者 ccl -o hello.s hello.i
编译器ccl 将文本文件hello.i 翻译为hello.s,这个文件里面包含一个汇编程序,如下

.file "hello.c"
.section .rodata
.LC0:
.string "hello, world"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
subl $16, %esp
movl $.LC0, (%esp)
call puts
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
.section .note.GNU-stack,"",@progbits

汇编语言是非常有用的,因为它将不同高级语言的不同编译器提供了通用的输出语言。例如,C和Fortran 的在此步编译产生的输出文件都是一样的汇编语言。
第三步、汇编阶段
执行命令: gcc -o hello.o -c hello.s
或者 as -o hello.o hello.s
汇编器as 将hello.s 翻译成机器语言保存在hello.o 中。这是个二进制文件,用命令hexdump hello.o 打开如下

0000000 457f 464c 0101 0001 0000 0000 0000 0000
0000010 0001 0003 0001 0000 0000 0000 0000 0000
0000020 011c 0000 0000 0000 0034 0000 0000 0028
0000030 000d 000a 8955 83e5 f0e4 ec83 c710 2404
0000040 0000 0000 fce8 ffff c9ff 00c3 6568 6c6c
0000050 2c6f 7720 726f 646c 0000 4347 3a43 2820
0000060 6255 6e75 7574 4c2f 6e69 7261 206f 2e34
0000070 2e36 2d33 7531 7562 746e 3575 2029 2e34
0000080 2e36 0033 0014 0000 0000 0000 7a01 0052
0000090 7c01 0108 0c1b 0404 0188 0000 001c 0000
00000a0 001c 0000 0000 0000 0017 0000 4100 080e
00000b0 0285 0d42 5305 0cc5 0404 0000 2e00 7973
00000c0 746d 6261 2e00 7473 7472 6261 2e00 6873
00000d0 7473 7472 6261 2e00 6572 2e6c 6574 7478
00000e0 2e00 6164 6174 2e00 7362 0073 722e 646f
00000f0 7461 0061 632e 6d6f 656d 746e 2e00 6f6e
0000100 6574 472e 554e 732d 6174 6b63 2e00 6572
0000110 2e6c 6865 665f 6172 656d 0000 0000 0000
0000120 0000 0000 0000 0000 0000 0000 0000 0000
*
0000140 0000 0000 001f 0000 0001 0000 0006 0000
0000150 0000 0000 0034 0000 0017 0000 0000 0000
0000160 0000 0000 0004 0000 0000 0000 001b 0000
0000170 0009 0000 0000 0000 0000 0000 03e8 0000
0000180 0010 0000 000b 0000 0001 0000 0004 0000
0000190 0008 0000 0025 0000 0001 0000 0003 0000
00001a0 0000 0000 004c 0000 0000 0000 0000 0000

第四步、链接阶段
执行命令: gcc -o hello hello.o
或者 ld -o hello hello.o
注意!hello程序调用了printf 函数,这个函数是标准C库中的一个函数,他保存在一个名为printf.o 的文件中,这个文件必须以某种方式合并到我们的hello.o的程序中。
链接器ld 负责处理这种合并。结果得到hello 可执行文件,可以被加载到内存中由系统执行。
./hello
总结
GCC编译器的工作过程:
源文件-->预处理-->编译/优化-->汇编-->链接-->可执行文件。
值得注意的是:我们在大学课本所学的编译原理是指高级语言程序编译生成汇编代码这一过程,并没有包含汇编和链接这一过程。汇编代码同样也需要经过汇编器来进行汇编,汇编器的全称是汇编编译器,也是编译器的一种。最后的链接是由链接器(Linker)完成的。
严格来说编译器只是将源代码转换成了目标代码,而链接器则将目标代码变成了可执行文件。但是我们平时并没有把编译器与链接器严格的区分出来,一般指的编译器是包含了链接这一功能的。
gcc编译器的工作流程的更多相关文章
- [Inside HotSpot] C1编译器工作流程及中间表示
1. C1编译器线程 C1编译器(aka Client Compiler)的代码位于hotspot\share\c1.C1编译线程(C1 CompilerThread)会阻塞在任务队列,当发现队列有编 ...
- GCC编译器使用
一.GCC简介 通常所说的GCC是GUN Compiler Collection的简称,除了编译程序之外,它还含其他相关工具,所以它能把易于人类使用的高级语言编写的源代码构建成计算机能够直接执行的二进 ...
- arm-linux-gcc 常用参数讲解 gcc编译器使用方法
我们需要编译出运行在ARM平台上的代码,所使用的交叉编译器为 arm-linux-gcc.下面将arm-linux-gcc编译工具的一些常用命令参数介绍给大家.在此之前首先介绍下编译器的工作过程,在使 ...
- windows下安装,配置gcc编译器
在Windows下使用gcc编译器: 1.首先介绍下MinGW MinGW是指仅仅用自由软件来生成纯粹的Win32可运行文件的编译环境,它是Minimalist GNU on Windows的略称. ...
- gcc编译器与基本类型3
C语言发展史 1969年贝尔实验室 肯尼斯·蓝·汤普逊,丹尼斯·李奇开发了B语言 ->Unix,New B语言,改名C语言83年提出C语言标准 1989年十二月正式通过C语言标准,C89标准 C ...
- C语言的本质(33)——GCC编译器入门
GCC(GNU CompilerCollection,GNU编译器套装),是由 GNU 开发的编程语言编译器.它是以GPL许可证所发行的自由软件,也是 GNU计划的关键部分.GCC原本作为GNU操作系 ...
- C语言_来了解一下GCC编译器编译C可执行脚本的过程
GCC简介 Linux系统下的gcc(GNU C Compiler)是GNU推出的功能强大.性能优越的多平台编译器,是GNU的代表作品之一.gcc是可以在多种硬体平台上编译出可执行程序的超级编译 ...
- GCC编译器原理(一)------交叉编译器制作和GCC组件及命令
1.1 交叉编译器制作 默认安装的 GCC 编译系统所产生的代码适用于本机,即运行 GCC 的机器,但也可将 GCC 安装成能够生成其他的机器代码.安装一些必须的模块,就可产生多种目标机器代码,而且可 ...
- 2、GCC编译器的使用
GCC编译器是一个非常强大和流行的C编译器,适用于各种Linux发行版.本文解释了一些流行的GCC编译器选项. GCC编译器选项 1.指定输出可执行文件名称 在最基本的形式中,gcc编译器可以用作: ...
随机推荐
- MariaDB/MySQL存储过程和函数
本文目录:1.创建存储过程.函数 1.1 存储过程的IN.OUT和INOUT2.修改和删除存储过程.函数3.查看存储过程.函数信息 在MySQL/MariaDB中,存储过程(stored proced ...
- 延迟确认和Nagle算法
前篇文章介绍了三次握手和四次挥手,了解了TCP是如何建立和断开连接的,文末还提到了抓包挥手时的一个“异常”现象,当时无法解释,特地查了资料,知道了数据传输中的延迟确认策略. 何谓延迟确认策略? WIK ...
- js window
window对象: browser object mode :bom对象. bom提供了独立于内容而与浏览器窗口进行交互的对象. bom主要用于管理窗口与窗口之间的通讯,因此其核心对象是window ...
- java之servlet小记
Servlet service+applet 服务+小程序 Java是语言,像c\c#等一样,是一门计算机语言,servlet是java ...
- emqtt 试用(九)ssl认证 - 客户端 mqttfx 验证
一.代码生成证书 1.安装openssl,配置path变量 安装文件:Win64OpenSSL-1_1_0f.exe 安装openssl:C:\OpenSSL-Win64 配置path变量:C:\Op ...
- SpringCloud应用入库后乱码问题
一.现象 1.请求 2.入库后 二.解决过程 1.配置application.properties 2.代码配置 3.数据库(关键!!) 3.请求 三.验证过程 1.win10 - 本地验证通过 2. ...
- shell多进程脚本
#!/bin/bash python_path=/home/huaw/crawler python_name=list_all_v6_crawler.py MAX_SYNC_PROCESS=40 ec ...
- 《Java面向对象设计》
<Java面向对象设计> 第一章 面向对象软件工程与UML p理解为什么需要软件工程 p掌握软件工程的基本概念 p掌握软件生命周期各个阶段的主要任务 p了解流行软件开发过程 p了解软件过程 ...
- JavaScript sort() 方法
定义和用法 sort() 方法用于对数组的元素进行排序. 语法 arrayObject.sort(sortby) 参数 描述 sortby 可选.规定排序顺序.必须是函数. 返回值 对数组的引用.请注 ...
- [Nginx]-外部多端口映射Https443端口配置
https服务器配置完成后,域名访问默认匹配至443端口,如果想同时通过https域名网址来请求多个对外服务,就需要在Nginx配置里来对请求进行规则判断,并匹配至相应的内部端口,这也是Nginx反向 ...