gcc编译过程简述

暗影侠客 暗影侠客     2022-08-19     644

关键词:

 

在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

 

 

总结

编译器的编译过程:
源文件-->预处理-->编译/优化-->汇编-->链接-->可执行文件。

平常用的最多、看起来一句命令就搞定的一次编译背后其实非常不简单。此博作简单记录,能力到了之后再做深入分析。

#---------------------------------------------------------------------------------#

参考文献

《Computer Systems: A Programmer's Perspective》 by Randal Bryant.

“编译过程” by itwilliamleehttp://www.lisdn.com/html/95/n-15195.html

gcc编译过程

gcc编译过程从hello.c到hello(或a.out)文件,必须历经hello.i、hello.s、hello.o,最后才得到hello(或a.out)文件,分别对应着预处理、编译、汇编和链接4个步骤,整个过程如图10.5所示。这4步大致的工作内容如下:(1)预处理,C编译器对各... 查看详情

gcc编译器原理------编译原理三:编译过程---预处理

Gcc的编译流程分为了四个步骤:预处理,生成预编译文件(.文件):gcc–Ehello.c–ohello.i编译,生成汇编代码(.s文件):gcc–Shello.i–ohello.s汇编,生成目标文件(.o文件):gcc–chello.s–ohello.o链接,生成可执行文件:gcchello.o–oh... 查看详情

gcc编译器原理------编译原理三:编译过程(2-1)---编译之词法分析

二、编译引用文档:https://blog.csdn.net/chdhust/article/details/9040647编译过程就是把预处理完的文件进行一系列词法分析、语法分析、语义分析及优化后生成相应的汇编代码文件,这个过程是整个程序构建的核心部分,也是最复杂的部... 查看详情

linux下详解gcc编译过程(含代码示例)&&gcc使用教程(代码片段)

文章目录准备:test.c1.编译过程1.1预处理(Pre-Processing)1.2汇编(Assembling)1.3编译(Compiling)*gcc-c1.4链接(Linking)2.简化过程——gcc3.gcc常用选项总结准备:test.c在正式开始之前,若是想要通过一个代码(.c文件)来熟悉gcc... 查看详情

gcc的编译过程

...成可执行文件gccdemo.c-odemo对于我们来说十分简单,但是对编译器来说却完成了一系列复杂的工作,概括起来有如下几步:1.预处理gcc-Edemo.c-odemo.i这一阶段主要处理源文件中的#ifdef、#include和#define等预处理命令demo.c->demo.i(经过预... 查看详情

linux编译工具:gcc温习

...改1.什么是gccgcc的全称是GNUCompilerCollection,它是一个能够编译多种语言的编译器。最开始gcc是作为C语言的编译器(GNUCCompiler),现在除了c语言,还支持C++、java、Pascal等语言。gcc支持多种硬件平台。2.gcc的特点gcc是一个可移植的... 查看详情

嵌入式开发gcc学习笔记-编译c程序及编译过程

一.C程序编译过程编译过程简单介绍:C语言的源文件编译成可运行文件须要四个步骤,预处理(Preprocessing)扩展宏,编译(compilation)得到汇编语言,汇编(assembly)得到机器码,连接(linking)得到可运行文件;--查看每一个步骤的编译细节:"-E"相应... 查看详情

system系统调用gcc编译过程

system库函数的功能是执行操作系统的命令或者运行指定的程序#include<stdio.h>#include<stdlib.h>//引入库intmain(){//system("notepad");//打开记事本system("dir");//查看目录  system("ipconfig");查看ipreturn0;}多线程pthread_createthread_cr 查看详情

gcc编译器原理------编译原理三:编译过程(2-2)---编译之语法分析

2.2语法分析语法分析器(GrammarParser)将对由扫描器产生的记号进行语法分析,从而产生语法树(SyntaxTree)。整个分析过程采用了上下文无关语法(Context-freeGrammar)的分析手段。由语法分析器生成的语法树就是以表达式(Expressio... 查看详情

求教:linux操作系统上安装gcc编译器过程?

参考技术A分类:电脑/网络解析:如果你用的是ubuntu,执行sudoapt-getinstallbuild-essentiallinux-headers-`uname-r`如果不是,你已经安装好了运行gcc--version检查一下 查看详情

请问linux下,gcc编译程序的过程(从读取源文件到制作可执行程序中间所有过程,越详细越好)

...开发工具.它们中的很多是用于C和C++应用程序开发的.GNUC编译器用gdb来调试GCC应用程序你也能看到随Linux发行的其他有用的C编程工具.这些工具包括源程序美化程序(prettyprintprograms),附加的调试工具,函数原型自动生成工具(automaticfunc... 查看详情

gcc编译链接过程(代码片段)

编译链接过程代码#catmain.c#include<stdio.h>intadd(intx,inty);intsub(intx,inty);intmul(intx,inty);intdiv(intx,inty);intmain(void)printf("add:%d",add(1,2));printf("sub:%d",sub(10,100));printf("mul:%d",mul(5,10));printf("div:%d",div(200,100));return0;===#catmath.c#include<stdio.h>in... 查看详情

gcc编译的过程(代码片段)

今天再次看了一下Linux下gcc编译的内部工作原理,决定写个博客加深一下自己的印象,如有错误欢迎大家指正。参考书籍《linuxc与c++一线开发实践》。gcc对c/c++语言的编译过程分为四个阶段:预处理、编译、汇编、链接。1,预处理... 查看详情

关于在centos中更新gcc的过程

...定的另一方面也意味着软件不会很快的更新,今天在准备编译u-boot时,显示gcc版本过低,而通过yum的更新还是达不到编译u-boot的要求,所以只能能从网上通过下在源码,手动编译安装gcc源码地址:  http://mirror.hust.edu.cn/gnu/gcc/... 查看详情

gcc编译器套件说明(代码片段)

...权请告知,马上删帖致歉。目录GCC简述GCC主要构成ARM编译工具链基于GCC的ARM编译工具链提供商ArmGNUToolchainLinaroToolchainReferenceGCC简述TheGNUCompilerCollection,通常简称GCC,是一套由GNU开发的编译器集合。为什么是编辑器集合... 查看详情

如何在linux中安装gcc编译器?

如何在linux中安装gcc编译器?2004年4月20日最新版本的GCC编译器3.4.0发布了。目前,GCC可以用来编译C/C++、FORTRAN、JAVA、OBJC、ADA等语言的程序,可根据需要选择安装支持的语言。GCC3.4.0比以前版本更好地支持了C++标准。本文以在Redhat... 查看详情

编译过程学习

...gcc命令就可以了。但是这其中包含了以下几个过程。1.预编译(preprocess)预编译过程主要是处理源代码中以#开头的预编译指令。如宏的处理,头文件的包含,注释删除,加入行号和文件名标识以使在编译时,编译器产生编译错误和... 查看详情

简述将源程序编译成可执行程序的过程

一个源程序到一个可执行程序的过程:预编译、编译、汇编、链接。其中,编译是主要部分,其中又分为六个部分:词法分析、语法分析、语义分析、中间代码生成、目标代码生成和优化。预编译:主要处理源代码文件中的以“... 查看详情