大家都知道编译的四个步骤:预处理、编译、汇编链接。但是这些步骤都是由谁完成的呢,今天做了几个实验验证一下。
(本人对编译和链接的原理不是很精通,以下内容是摸索的,难免出错。不要被我误导了)
首先编写一个简单的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
- Stand-alone CPP is dead. The compiler front end now handles preprocessed output if necessary.
- 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).
- CPP arithmetic is now done to the correct target precision, based upon the selected language standard.
- 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编译过程详解 #### 一、GCC简介与作用 GCC(GNU Compiler Collection)是GNU发布的一套编程语言编译器,它支持多种编程语言,如C、C++、Objective-C、Fortran等,并且可以针对不同的处理器架构生成优化过的...
嵌入式程序设计基础GCC编译过程讲解 GCC(GNU Compiler Collection)是GNU项目的核心组件,主要用于嵌入式系统开发,支持多种编程语言,如C、C++等,并且能够跨平台编译,适应多种CPU架构,如X86、ARM7、StrongARM...
本篇主要聚焦于GCC的编译过程,这是一个将源代码转换为可执行程序的过程,主要包括四个主要步骤:预处理、编译、汇编和链接。 1. **预处理**: 预处理是GCC的第一步,通过`gcc -E`或`cpp`命令执行。在这个阶段,...
这个压缩包包含的文件展示了GCC编译过程的不同阶段,让我们逐一分析这些文件及其背后的编译原理。 1. **hello.c** 这是源代码文件,通常用C语言编写。在这个例子中,它可能包含了一个简单的“Hello, World!”程序...
GNU集成编译环境GCC(GNU Compiler Collection)是一种面向嵌入式领域、支持多种编程...GCC编译过程 C/C++交叉编译器arm-elf-gcc 交叉汇编器 arm-elf-as 交叉连接器arm-elf-l d 工程管理器make 汇编语言编程 混合编程
同时,了解GCC编译过程、调试技巧以及如何适配不同MCU的特性也是嵌入式开发的基础技能。在VSCode中,利用其丰富的插件和扩展功能,可以进一步提升开发体验,如添加代码高亮、自动完成、错误检查等。
GCC编译优化选项详解 GCC(GNU Compiler Collection)是GNU项目的一部分,用于将源代码转换为机器可执行的指令。GCC提供了丰富的编译优化选项,旨在提升程序的运行效率和代码大小,同时在一定程度上牺牲编译时间和...
使用这些工具可以帮助简化Windows上的GCC编译过程,提供一键式安装和配置。 总的来说,Windows下的GCC编译涉及多个层面,从环境搭建、语言混编到调试和优化,都需要一定的技巧和经验。了解并掌握这些知识点,对于...
这三个库是GCC编译过程中用于增强其处理浮点数和大整数能力的关键组件。 1. GMP(GNU Multiple Precision Arithmetic Library): GMP是GNU项目的一部分,是一个高效且灵活的大整数运算库。它提供了一种在C和C++中...
标题 "nordic52832 nordic使用gcc编译环境搭建资料合集20220506 085836" 涉及的是为Nordic 52832微控制器搭建基于GCC的编译环境。...在实际开发过程中,理解编译过程、了解芯片特性、掌握调试技巧都是必不可少的技能。
预处理是GCC编译过程中最初始的阶段。在这个阶段,GCC会处理以`#`字符开头的预处理器指令。预处理器的主要任务包括: - **宏替换**:对宏进行展开,例如`#define`定义的宏会被相应的文本替换。 - **文件包含**:...
在编译过程中,预处理阶段会处理宏定义、条件编译等;编译阶段将源代码转化为汇编代码;汇编阶段将汇编代码转化为机器码;链接阶段则将多个目标文件合并成一个可执行文件,同时处理符号引用和重定位。 FreeRTOS的...
GCC 编译指南提供了多种参数选项,用于控制编译过程的各个阶段。下面对 GCC 编译指南的使用方法进行详细介绍。 基本用法 GCC 编译指南的基本用法是:gcc [options] [filenames]。其中,options 是编译器的选项,...
GCC编译数据库并不是一个传统意义上的数据库,而是一种存储项目编译指令的数据结构或文件格式,通常用于记录编译过程中使用的命令行选项。这种数据库有助于自动化工具理解如何编译项目中的每个源文件,从而简化了...
GCC 编译命令是 GCC 编译器的命令行接口,它提供了一系列选项和参数来控制编译过程。GCC 编译命令的基本格式为: gcc [options] [source_files] -o [output_file] 其中,options 是可选的编译选项,source_files ...
本文将详细讲解Linux下GCC的编译过程,包括预处理、编译、汇编和链接四个阶段,并探讨相关的编译选项和优化原理。 1. 预处理 预处理是GCC处理C源代码的第一步,由cpp程序负责。在这个阶段,GCC执行以下操作: - ...
#### 二、GCC编译过程介绍 GCC的编译过程大致可以分为以下几个步骤:预处理、编译、汇编和链接。下面详细介绍每个阶段的作用: 1. **预处理**(Preprocessing):在这个阶段,GCC会读取源代码文件,并处理其中的预...
C语言再学习 -- GCC编译过程-附件资源
以下是arm-linux-gcc编译选项的详细知识点说明: 1. 编译过程的四个阶段: - 预处理阶段:GCC会对源文件进行预处理,展开宏定义、处理条件编译指令、包含头文件等。 - 编译阶段:经过预处理的源文件会被转化为...