本以为gcc
会调用cc1
、as
和ld
来完成一系列编译、汇编和链接的工作,实际上,gcc
是通过collect2
间接调用ld的。
collect2
主要实现了两个额外的功能,都是为C++
程序准备的。其一是生成代码调用全局静态对象的构造函数和析构函数;其二是支持Cfront
方式生成模板代码。
C++
程序的全局静态对象,需要在main
函数运行前构造好,在main
函数执行完成后析构掉。构造函数和析构函数是由程序员编写的,那么该由谁负责调用呢?通常来讲,调用这些函数的工作由初始化代码完成,比如,GNU ld
就可以生成这些代码。如果这些代码不能由linker自动生成,就需要collect2
的帮助。
collect2
调用ld
生成一个执行程序,然后调用nm
程序,根据命名规则,查找所有的调用全局静态对象构造函数和析构函数的函数,并将这些函数保存为一张表,再生成一段代码遍历每个表项,调用对应的函数。所有这些信息被保存为一个C
程序,然后编译、汇编为目标文件,在链接时作为第一个目标文件传给linker,做第二次链接。此功能实现在gcc/collect2.c
文件内。通过在config.gcc
文件里查找use_collect2=yes
来确定哪些系统使用了该功能,PC上默认是关闭的。
Cfront
支持代码实现在gcc/tlink.c
文件里,这里的调用关系就更复杂了。gcc
在编译C++
程序时不生成任何模板代码,而是使用-frepo
生成一个辅助文件,collect2
调用ld
做链接后,分析错误信息,提取未定义的符号,然后通过分析所有的repo文件,判断要生成哪些模板代码,并调用gcc
重新编译特定文件,然后再链接,如果还有未定义的符号,则重复上述过程。如此反复,最多17次。如果还不能正确链接,则报错。
查看collect2
的手册
info gccint 'collect2'
查看Cfront
模型
info gcc 'C++ Extensions' 'Template Instantiation'
One thought on “collect2”