`
isiqi
  • 浏览: 16560102 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

gcc的编译过程

阅读更多

大家都知道编译的四个步骤:预处理、编译、汇编链接。但是这些步骤都是由谁完成的呢,今天做了几个实验验证一下。

(本人对编译和链接的原理不是很精通,以下内容是摸索的,难免出错。不要被我误导了)

首先编写一个简单的C文件,比如"hello, world!",然后使用-v选项来编译它,这样它的编译步骤就可以显示出来了。

[zlg@localhost gdbtest]$ gcc -v //显示gcc的版本信息
Using built-in specs.
Target: i386-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-cpu=generic --build=i386-redhat-linux
Thread model: posix
gcc version 4.3.2 20081105 (Red Hat 4.3.2-7) (GCC)

[zlg@localhost gdbtest]$ gcc -v main.c //使用-v选项编译main.c
Using built-in specs.
Target: i386-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-cpu=generic --build=i386-redhat-linux
Thread model: posix
gcc version 4.3.2 20081105 (Red Hat 4.3.2-7) (GCC)

COLLECT_GCC_OPTIONS='-v' '-mtune=generic'
/usr/libexec/gcc/i386-redhat-linux/4.3.2/cc1 -quiet -v main.c -quiet -dumpbase main.c -mtune=generic -auxbase main -version -o /tmp/ccCwWqS3.s /*生成临时的汇编文件*/
ignoring nonexistent directory "/usr/lib/gcc/i386-redhat-linux/4.3.2/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/i386-redhat-linux/4.3.2/../../../../i386-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here: /*头文件的搜索目录*/
/usr/local/include
/usr/lib/gcc/i386-redhat-linux/4.3.2/include
/usr/include
End of search list.
GNU C (GCC) version 4.3.2 20081105 (Red Hat 4.3.2-7) (i386-redhat-linux)
compiled by GNU C version 4.3.2 20081105 (Red Hat 4.3.2-7), GMP version 4.2.2, MPFR version 2.3.2.
GGC heuristics: --param ggc-min-expand=59 --param ggc-min-heapsize=55617
Compiler executable checksum: 3bee52601079f736b7b63b762646f4ba
COLLECT_GCC_OPTIONS='-v' '-mtune=generic'
as -V -Qy -o /tmp/cca2z171.o /tmp/ccCwWqS3.s /*调用汇编器生成目标代码*/
GNU assembler version 2.18.50.0.9 (i386-redhat-linux) using BFD version version 2.18.50.0.9-7.fc10 20080822 /*汇编器版本信息*/
COMPILER_PATH=/usr/libexec/gcc/i386-redhat-linux/4.3.2/:/usr/libexec/gcc/i386-redhat-linux/4.3.2/:/usr/libexec/gcc/i386-redhat-linux/:/usr/lib/gcc/i386-redhat-linux/4.3.2/:/usr/lib/gcc/i386-redhat-linux/:/usr/libexec/gcc/i386-redhat-linux/4.3.2/:/usr/libexec/gcc/i386-redhat-linux/:/usr/lib/gcc/i386-redhat-linux/4.3.2/:/usr/lib/gcc/i386-redhat-linux/
LIBRARY_PATH=/usr/lib/gcc/i386-redhat-linux/4.3.2/:/usr/lib/gcc/i386-redhat-linux/4.3.2/:/usr/lib/gcc/i386-redhat-linux/4.3.2/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-mtune=generic'
/*collect2完成最后的链接工作*/
/usr/libexec/gcc/i386-redhat-linux/4.3.2/collect2 --eh-frame-hdr --build-id -m elf_i386 --hash-style=gnu -dynamic-linker /lib/ld-linux.so.2 /usr/lib/gcc/i386-redhat-linux/4.3.2/../../../crt1.o /usr/lib/gcc/i386-redhat-linux/4.3.2/../../../crti.o /usr/lib/gcc/i386-redhat-linux/4.3.2/crtbegin.o -L/usr/lib/gcc/i386-redhat-linux/4.3.2 -L/usr/lib/gcc/i386-redhat-linux/4.3.2 -L/usr/lib/gcc/i386-redhat-linux/4.3.2/../../.. /tmp/cca2z171.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i386-redhat-linux/4.3.2/crtend.o /usr/lib/gcc/i386-redhat-linux/4.3.2/../../../crtn.o

总结一下编译过程:
启动/usr/bin/gcc
/usr/libexec/gcc/i386-redhat-linux/4.3.2/cc1 进行预处理和编译,生成的临时汇编文件放在/tmp
/usr/bin/as 将上一步的汇编文件生成临时目标文件放在/tmp
/usr/libexec/gcc/i386-redhat-linux/4.3.2/collect2 调用连接器/usr/bin/ld生成可执行文件

注意,没有一个单独的预处理工具,预处理和编译的工作由ccl完成。ccl生成的临时汇编文件在/tmp下:/tmp/ccCwWqS3.s
as是汇编器,负责生成目标文件。目标文件依然作为临时文件存放在/tmp下面: /tmp/cca2z171.o
最后调用collect2负责链接的工作。collect2针对C++程序进行特殊处理。

collect2的信息参考:
gnu官方collect2的文档:http://gcc.gnu.org/onlinedocs/gccint/Collect2.html
别人的博客:http://hellogcc.blogbus.com/logs/67096640.html /// http://alpha-blog.wanglianghome.org/2011/04/14/collect2/

对于gcc\ccl\collect2等关系的描述参考:《gcc的组件和软件工具》http://hi.baidu.com/xuelicheng/blog/item/cd5650505ecaea658535241a.html
gcc\as\ld的相关知识参考:http://www.cppblog.com/jinglexy/archive/2007/04/19/22298.html

知识点补充:

[zlg@localhost gdbtest]$ ls /usr/libexec/gcc/i386-redhat-linux/4.3.2/
cc1 cc1plus collect2 f951
[zlg@localhost gdbtest]$

实验1:验证collect2会调用链接器ld.
[zlg@localhost gdbtest]$ /usr/libexec/gcc/i386-redhat-linux/4.3.2/collect2 -v
collect2 version 4.3.2 20081105 (Red Hat 4.3.2-7) (i386 Linux/ELF)
/usr/bin/ld -v
GNU ld version 2.18.50.0.9-7.fc10 20080822
[zlg@localhost gdbtest]$

实验2:CPP的实现依赖于cc1

http://gcc.gnu.org/projects/cpplib.html

有这么一段话:

Work recently completed

  1. Stand-alone CPP is dead. The compiler front end now handles preprocessed output if necessary.
  2. As many built-in macros as possible have been moved to the front ends, and out of SPECS and cpplib itself (some targets still in progress).
  3. CPP arithmetic is now done to the correct target precision, based upon the selected language standard.
  4. The traditional preprocessor has been integrated into cpplib. At present it is an output-only preprocessor, but it should be fairly simple to modify cpplib so that traditional preprocessing and then tokenization are performed in one invocation.

这段话的意思是CPP(也就是C语言预处理器)不再独立存在,已经被合并进了cpplib。现在由编译器前端工具负责调用。

在Linux系统(fedora10)上可用的CPP有两个,/lib/cpp和/usr/bin/cpp,其中前者是后者的符号链接。将/usr/bin/cpp改为别的名字,GCC照常编译,这说明/usr/bin/cpp并不会被GCC调用 。但是经过验证,“/usr/bin/cpp main.c”的确可以对C文件做预处理。

接下来再做实验:

[root@localhost gdbtest]# /usr/bin/cpp -v
Using built-in specs.
Target: i386-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-cpu=generic --build=i386-redhat-linux
Thread model: posix
gcc version 4.3.2 20081105 (Red Hat 4.3.2-7) (GCC)
COLLECT_GCC_OPTIONS='-E' '-v' '-mtune=generic'
/usr/libexec/gcc/i386-redhat-linux/4.3.2/ cc1 -E -quiet -v - -mtune=generic
ignoring nonexistent directory "/usr/lib/gcc/i386-redhat-linux/4.3.2/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/i386-redhat-linux/4.3.2/../../../../i386-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/local/include
/usr/lib/gcc/i386-redhat-linux/4.3.2/include
/usr/include
End of search list.

可以看到,向cpp传递-v选项,竟然会启动cc1,这说明cpp调用了cc1。最重要的是,向cpp传入-v选项,cpp给cc1的参数中竟然有-E选项,这说明cc1才是预处理的主体,cpp的默认动作就是将-E参数传给cc1,它自己啥也做不了。

以前cpp是一个独立的预处理器,现在cpp仅仅是一个依赖于cc1的封装接口 。cc1才是做预处理的地方。

实验3:验证预处理和编译都是由cc1完成的。并且预处理不生成临时文件
[zlg@localhost gdbtest]$ gcc -v -E main.c > main.i /*仅仅进行预处理*/
Using built-in specs.
Target: i386-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-cpu=generic --build=i386-redhat-linux
Thread model: posix
gcc version 4.3.2 20081105 (Red Hat 4.3.2-7) (GCC)
COLLECT_GCC_OPTIONS='-v' '-E' '-mtune=generic'
/usr/libexec/gcc/i386-redhat-linux/4.3.2/cc1 -E -quiet -v main.c -mtune=generic
ignoring nonexistent directory "/usr/lib/gcc/i386-redhat-linux/4.3.2/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/i386-redhat-linux/4.3.2/../../../../i386-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/local/include
/usr/lib/gcc/i386-redhat-linux/4.3.2/include
/usr/include
End of search list.
COMPILER_PATH=/usr/libexec/gcc/i386-redhat-linux/4.3.2/:/usr/libexec/gcc/i386-redhat-linux/4.3.2/:/usr/libexec/gcc/i386-redhat-linux/:/usr/lib/gcc/i386-redhat-linux/4.3.2/:/usr/lib/gcc/i386-redhat-linux/:/usr/libexec/gcc/i386-redhat-linux/4.3.2/:/usr/libexec/gcc/i386-redhat-linux/:/usr/lib/gcc/i386-redhat-linux/4.3.2/:/usr/lib/gcc/i386-redhat-linux/
LIBRARY_PATH=/usr/lib/gcc/i386-redhat-linux/4.3.2/:/usr/lib/gcc/i386-redhat-linux/4.3.2/:/usr/lib/gcc/i386-redhat-linux/4.3.2/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-E' '-mtune=generic'
[zlg@localhost gdbtest]$ gcc main.c -S -v /*直接生成汇编文件*/
Using built-in specs.
Target: i386-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-cpu=generic --build=i386-redhat-linux
Thread model: posix
gcc version 4.3.2 20081105 (Red Hat 4.3.2-7) (GCC)
COLLECT_GCC_OPTIONS='-S' '-v' '-mtune=generic'
/usr/libexec/gcc/i386-redhat-linux/4.3.2/cc1 -quiet -v main.c -quiet -dumpbase main.c -mtune=generic -auxbase main -version -o main.s
ignoring nonexistent directory "/usr/lib/gcc/i386-redhat-linux/4.3.2/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/i386-redhat-linux/4.3.2/../../../../i386-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/local/include
/usr/lib/gcc/i386-redhat-linux/4.3.2/include
/usr/include
End of search list.
GNU C (GCC) version 4.3.2 20081105 (Red Hat 4.3.2-7) (i386-redhat-linux)
compiled by GNU C version 4.3.2 20081105 (Red Hat 4.3.2-7), GMP version 4.2.2, MPFR version 2.3.2.
GGC heuristics: --param ggc-min-expand=59 --param ggc-min-heapsize=55617
Compiler executable checksum: 3bee52601079f736b7b63b762646f4ba
COMPILER_PATH=/usr/libexec/gcc/i386-redhat-linux/4.3.2/:/usr/libexec/gcc/i386-redhat-linux/4.3.2/:/usr/libexec/gcc/i386-redhat-linux/:/usr/lib/gcc/i386-redhat-linux/4.3.2/:/usr/lib/gcc/i386-redhat-linux/:/usr/libexec/gcc/i386-redhat-linux/4.3.2/:/usr/libexec/gcc/i386-redhat-linux/:/usr/lib/gcc/i386-redhat-linux/4.3.2/:/usr/lib/gcc/i386-redhat-linux/
LIBRARY_PATH=/usr/lib/gcc/i386-redhat-linux/4.3.2/:/usr/lib/gcc/i386-redhat-linux/4.3.2/:/usr/lib/gcc/i386-redhat-linux/4.3.2/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-S' '-v' '-mtune=generic'

分享到:
评论

相关推荐

    gcc编译过程概述.pdf

    ### GCC编译过程详解 #### 一、GCC简介与作用 GCC(GNU Compiler Collection)是GNU发布的一套编程语言编译器,它支持多种编程语言,如C、C++、Objective-C、Fortran等,并且可以针对不同的处理器架构生成优化过的...

    嵌入式程序设计基础GCC编译过程PPT学习教案.pptx

    嵌入式程序设计基础GCC编译过程讲解 GCC(GNU Compiler Collection)是GNU项目的核心组件,主要用于嵌入式系统开发,支持多种编程语言,如C、C++等,并且能够跨平台编译,适应多种CPU架构,如X86、ARM7、StrongARM...

    gcc编译过程

    本篇主要聚焦于GCC的编译过程,这是一个将源代码转换为可执行程序的过程,主要包括四个主要步骤:预处理、编译、汇编和链接。 1. **预处理**: 预处理是GCC的第一步,通过`gcc -E`或`cpp`命令执行。在这个阶段,...

    gcc编译原理例子文件

    这个压缩包包含的文件展示了GCC编译过程的不同阶段,让我们逐一分析这些文件及其背后的编译原理。 1. **hello.c** 这是源代码文件,通常用C语言编写。在这个例子中,它可能包含了一个简单的“Hello, World!”程序...

    嵌入式程序设计基础(GCC编译过程,C/C++交叉编译器arm-elf-gcc,工程管理器make)

    GNU集成编译环境GCC(GNU Compiler Collection)是一种面向嵌入式领域、支持多种编程...GCC编译过程 C/C++交叉编译器arm-elf-gcc 交叉汇编器 arm-elf-as 交叉连接器arm-elf-l d 工程管理器make 汇编语言编程 混合编程

    GD32F407-GCC编译模板,包含配置文件

    同时,了解GCC编译过程、调试技巧以及如何适配不同MCU的特性也是嵌入式开发的基础技能。在VSCode中,利用其丰富的插件和扩展功能,可以进一步提升开发体验,如添加代码高亮、自动完成、错误检查等。

    gcc 编译 优化 选项

    GCC编译优化选项详解 GCC(GNU Compiler Collection)是GNU项目的一部分,用于将源代码转换为机器可执行的指令。GCC提供了丰富的编译优化选项,旨在提升程序的运行效率和代码大小,同时在一定程度上牺牲编译时间和...

    windows下gcc编译

    使用这些工具可以帮助简化Windows上的GCC编译过程,提供一键式安装和配置。 总的来说,Windows下的GCC编译涉及多个层面,从环境搭建、语言混编到调试和优化,都需要一定的技巧和经验。了解并掌握这些知识点,对于...

    gcc编译需要的三个库gmp/mpc/mpfr

    这三个库是GCC编译过程中用于增强其处理浮点数和大整数能力的关键组件。 1. GMP(GNU Multiple Precision Arithmetic Library): GMP是GNU项目的一部分,是一个高效且灵活的大整数运算库。它提供了一种在C和C++中...

    nordic52832 nordic使用gcc编译环境搭建资料合集20220506 085836

    标题 "nordic52832 nordic使用gcc编译环境搭建资料合集20220506 085836" 涉及的是为Nordic 52832微控制器搭建基于GCC的编译环境。...在实际开发过程中,理解编译过程、了解芯片特性、掌握调试技巧都是必不可少的技能。

    GCC的编译流程

    预处理是GCC编译过程中最初始的阶段。在这个阶段,GCC会处理以`#`字符开头的预处理器指令。预处理器的主要任务包括: - **宏替换**:对宏进行展开,例如`#define`定义的宏会被相应的文本替换。 - **文件包含**:...

    gcc编译stm32f103+freeROTS代码

    在编译过程中,预处理阶段会处理宏定义、条件编译等;编译阶段将源代码转化为汇编代码;汇编阶段将汇编代码转化为机器码;链接阶段则将多个目标文件合并成一个可执行文件,同时处理符号引用和重定位。 FreeRTOS的...

    LINUX下的GCC编译指南

    GCC 编译指南提供了多种参数选项,用于控制编译过程的各个阶段。下面对 GCC 编译指南的使用方法进行详细介绍。 基本用法 GCC 编译指南的基本用法是:gcc [options] [filenames]。其中,options 是编译器的选项,...

    gcc编译数据库1

    GCC编译数据库并不是一个传统意义上的数据库,而是一种存储项目编译指令的数据结构或文件格式,通常用于记录编译过程中使用的命令行选项。这种数据库有助于自动化工具理解如何编译项目中的每个源文件,从而简化了...

    GCC编译命令 Gcc命令行详解

    GCC 编译命令是 GCC 编译器的命令行接口,它提供了一系列选项和参数来控制编译过程。GCC 编译命令的基本格式为: gcc [options] [source_files] -o [output_file] 其中,options 是可选的编译选项,source_files ...

    linux Gcc 编译详解

    本文将详细讲解Linux下GCC的编译过程,包括预处理、编译、汇编和链接四个阶段,并探讨相关的编译选项和优化原理。 1. 预处理 预处理是GCC处理C源代码的第一步,由cpp程序负责。在这个阶段,GCC执行以下操作: - ...

    gcc交叉编译工具基础知识

    #### 二、GCC编译过程介绍 GCC的编译过程大致可以分为以下几个步骤:预处理、编译、汇编和链接。下面详细介绍每个阶段的作用: 1. **预处理**(Preprocessing):在这个阶段,GCC会读取源代码文件,并处理其中的预...

    C语言再学习 -- GCC编译过程-附件资源

    C语言再学习 -- GCC编译过程-附件资源

    arm-linux-gcc编译选项.pdf

    以下是arm-linux-gcc编译选项的详细知识点说明: 1. 编译过程的四个阶段: - 预处理阶段:GCC会对源文件进行预处理,展开宏定义、处理条件编译指令、包含头文件等。 - 编译阶段:经过预处理的源文件会被转化为...

Global site tag (gtag.js) - Google Analytics