程序的本质之一程序编译的详细过程

操作系统:CentOS Linux release 7.7.1908

内核版本:3.10.0-1062.1.1.el7.x86_64

运行平台:x86_64

 

为了在64位的操作系统中编译32位的应用程序,可能须要安装以下动态库:

$ sudo yum install glibc.i686
$ sudo yum install glibc-devel.i686
$ sudo yum install libgcc.i686

C/C++程序的编译过程大致分为编译、汇编和链接等三个过程。执行gcc命令编译源文件tanglinux.c如下所示:

$ gcc --verbose -m32 tanglinux.c -o tanglinux

其中,-m32表示编译32位的应用程序,--verbose(也就是-v)表示显示编译时的详细过程。

源文件tanglinux.c的代码如下所示:

int main()
{
    return 0;
}

编译的详细过程如下所示:

Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/lto-wrapper
Target: x86_64-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-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux
Thread model: posix
gcc version 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC) 
COLLECT_GCC_OPTIONS='-v' '-m32' '-o' 'tanglinux' '-mtune=generic' '-march=x86-64'
 /usr/libexec/gcc/x86_64-redhat-linux/4.8.5/cc1 -quiet -v -imultilib 32 tanglinux.c -quiet -dumpbase tanglinux.c -m32 -mtune=generic -march=x86-64 -auxbase tanglinux -version -o /tmp/cc04RaVm.s
GNU C (GCC) version 4.8.5 20150623 (Red Hat 4.8.5-39) (x86_64-redhat-linux)
        compiled by GNU C version 4.8.5 20150623 (Red Hat 4.8.5-39), GMP version 6.0.0, MPFR version 3.1.1, MPC version 1.0.1
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../x86_64-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-redhat-linux/4.8.5/include
 /usr/local/include
 /usr/include
End of search list.
GNU C (GCC) version 4.8.5 20150623 (Red Hat 4.8.5-39) (x86_64-redhat-linux)
        compiled by GNU C version 4.8.5 20150623 (Red Hat 4.8.5-39), GMP version 6.0.0, MPFR version 3.1.1, MPC version 1.0.1
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: edd9a53947039836c859e437e8c9af72
COLLECT_GCC_OPTIONS='-v' '-m32' '-o' 'tanglinux' '-mtune=generic' '-march=x86-64'
 as -v --32 -o /tmp/ccACvBBI.o /tmp/cc04RaVm.s
GNU assembler version 2.27 (x86_64-redhat-linux) using BFD version version 2.27-41.base.el7
COMPILER_PATH=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/:/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/:/usr/libexec/gcc/x86_64-redhat-linux/:/usr/lib/gcc/x86_64-redhat-linux/4.8.5/:/usr/lib/gcc/x86_64-redhat-linux/
LIBRARY_PATH=/usr/lib/gcc/x86_64-redhat-linux/4.8.5/32/:/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-redhat-linux/4.8.5/:/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-m32' '-o' 'tanglinux' '-mtune=generic' '-march=x86-64'
 /usr/libexec/gcc/x86_64-redhat-linux/4.8.5/collect2 --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o tanglinux /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib/crt1.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib/crti.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/32/crtbegin.o -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/32 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../.. /tmp/ccACvBBI.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-redhat-linux/4.8.5/32/crtend.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib/crtn.o

其中,程序lto-wrapper只是lto1程序的封装,用于实现Link-Time Optimization(LTO)功能,即链接时优化。详情可参考网址https://gcc.gnu.org/wiki/LinkTimeOptimization

从以“Configured with:”开头的行可查看所使用的gcc自身编译时所使用的选项。

编译C语言程序的cc1和编译C++语言程序的cc1plus都需要GMP(The GNU Multiple Precision Arithmetic Library)、MPFR和MPC等三个库的支持。MPC基于MPFR,而MPFR又基于GMP。GMP是针对有符号整数、有理数和浮点数的高精度的运算库。而MPFR只针对浮点数并且能正确舍入,MPC针对复数。

GGC (the GCC Garbage Collector),即垃圾收集器插件,用于管理gcc自身的内存分配。ggc-min-expand选项为ggc所使用的堆内存的最小扩展百分比,ggc-min-heapsize选项为ggc所使用的堆内存的最小字节数(单位为KiB)。

从编译的过程信息中,也能看出头文件和依赖库所查询的目录。

去除不必要的过程信息后,程序编译的三个过程其实是如下所示:

cc1 -quiet -v -imultilib 32 tanglinux.c -quiet -dumpbase tanglinux.c -m32 -mtune=generic -march=x86-64 -auxbase tanglinux -version -o cc04RaVm.s
as -v --32 -o ccACvBBI.o cc04RaVm.s
collect2 --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu -m elf_i386 -dynamic-linker ld-linux.so.2 -o tanglinux crt1.o crti.o crtbegin.o ccACvBBI.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed crtend.o crtn.o

其中,C语言程序实质的编译程序为cc1;链接程序为collect2,它会调用实质的链接程序ld。cc1和collect2属于GCC项目,而as和ld属于GNU的Binutils项目。

编译选项-quiet表示不显示编译过程;选项-imultilib将所指定的值作为搜索的子目录;选项-dumpbase表示设置用于转储的文件基名,选项-auxbase也是将后面所列的值作为某种用途的文件的基本名;选项-m32表示生成32位的i386平台的代码;选项-march和-mtune用于指定硬件平台。

汇编选项--32表示使用i386体系结构。

链接选项--build-id表示为ELF文件创建名称为“.note.gnu.build-id”的note section,其主要内容为使用SHA1散列算法计算所得的20个字节的ID号;选项--no-add-needed被--no-copy-dt-needed-entries替代,表示不拷贝命令行中所列动态库中的DT_NEEDED表项;选项--as-needed使最终所生成的可执行文件中的动态链接表.dynamic的DT_NEEDED表项只记录真正用到的动态库(选择范围为命令行中位于该选项之后的动态库),选项--no-as-needed则恢复默认行为;选项--eh-frame-hdr表示创建名为.eh_frame_hdr的section以及名为PT_GNU_EH_FRAME的segment header;选项--hash-style的值为gnu时表示创建名为.gnu.hash的section;选项-m表示生成elf_i386格式的可执行文件;选项--dynamic-linker表示可执行文件将要使用的动态链接器,记录在可执行文件的.interp section中;最后还链接了crt1.o、crti.o、crtbegin.o、crtend.o和crtn.o等五个目标文件。

执行以下命令可以查看collect2的版本及其实质所使用的链接程序ld的版本:

$ /usr/libexec/gcc/x86_64-redhat-linux/4.8.5/collect2 --version
collect2 version 4.8.5 20150623 (Red Hat 4.8.5-39)
/usr/bin/ld --version
GNU ld version 2.27-41.base.el7
Copyright (C) 2016 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) a later version.
This program has absolutely no warranty.

然而,实际上/usr/bin/ld还不是最终的链接程序,它只是一个符号链接文件,链接到/etc/alternatives/ld文件,而后/etc/alternatives/ld又链接到/usr/bin/ld.bfd文件,这个ld.bfd文件才是真正的链接程序。

$ file /usr/bin/ld
/usr/bin/ld: symbolic link to `/etc/alternatives/ld'

$ file /etc/alternatives/ld 
/etc/alternatives/ld: symbolic link to `/usr/bin/ld.bfd'

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tanglinux

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值