您的位置:首页 > 其它

gcc的编译过程

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

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



首先编写一个简单的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'
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: