编译链接实战(12)crt1.o, crti.o, crtbegin.o, crtend.o, crtn.o是什么东西

Posted 奇妙之二进制

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了编译链接实战(12)crt1.o, crti.o, crtbegin.o, crtend.o, crtn.o是什么东西相关的知识,希望对你有一定的参考价值。

crt是c runtime 的缩写,用于执行进入main之前的初始化和退出main之后的扫尾工作。

crt1.o, crti.o, crtbegin.o, crtend.o, crtn.o 等目标文件和daemon.o(由我们自己的C程序文件产生)链接成一个执行文件。
前面这5个目标文件的作用分别是启动、初始化、构造、析构和结束,它们 通常会被自动链接到应用程序中

So,在标准的linux平台下,link的顺序是:ld crt1.o crti.o [user_objects] [system_libraries] crtn.o

crt1.o中包含程 序的入口函数_start以及两个未定义的符号__libc_start_main和main,由_start负责调用 __libc_start_main初始化libc,然后调用我们源代码中定义的main函数;
另外,由于类似于全局静态对象这样的代码需要在main函 数之前执行,crti.o和crtn.o负责辅助启动这些代码。
另外,Gcc中同样也有crtbegin.o和crtend.o两个文件,这两个目标文件 用于配合glibc来实现C++的全局构造和析构。

crt1.o是crt0.o的后续演进版本,crt1.o中会非常重要的.init段和.fini 段以及_start函数的入口…init段和.fini段实际上是靠crti.o以及crtn.o来实现的. init段是main函数之前的初始化工作代码, 比如全局变量的构造.

fini段则负责main函数之后的清理工作.crti.o crtn.o是负责C的初始化,而C++则必须依赖crtbegin.o和crtend.o来帮助实现.

main()也是一个函数。

这 是因为在编译连接时它将会作为crt0.s汇编程序的函数被调用。crt0.s是一个桩(stub)程序,名称中的“crt”是“C run-time”的缩写。该程序的目标文件将被链接在每个用户执行程序的开始部分,主要用于设置一些初始化全局变量。通常使用gcc编译链接生成文件 时,gcc会自动把该文件的代码作为第一个模块链接在可执行程序中。在编译时使用显示详细信息选项“-v”就可以明显地看出这个链接操作过程。因此在通常 的编译过程中,我们无需特别指定stub模块crt0.o。为了使用ELF格式的目标文件以及建立共享库模块文件,现在的编译器已经把crt0扩展成几个 模块:crt1.0、crti.o、crtbegin.o、crtend.o和crtn.o。 这些模块的链接顺序为crt1.o、crti.o、crtbegin.o(crtbeginS.o)、所有程序模块、 crtend.o(crtendS.o)、crtn.o、库模块文件。

gcc的配置文件specfile指定了这种链接顺序。其中,crt1.o、 crti.o和crtn.o由C库提供,是C程序的“启动”模块;crtbegin.o和crtend.o是C++语言的启动模块,由编译器gcc提供;

而crt1.o则与crt0.o的作用类似,主要用于在调用main()之前做一些初始化工作,全局符号_start就定义在这个模块中。

crtbegin.o和crtend.o主要用于C++语言,在.ctors和.dtors区中执行全局构造(constructor)和析构 (destructor)函数。
crtbeginS.o和crtendS.o的作用与前两者类似,但用于创建共享模块中。crti.o用于在.init区 中执行初始化函数init()。
.init区中包含进程的初始化代码,即当程序开始执行时,系统会在调用main()之前先执行.init中的代码。

crtn.o则用于在.fini区中执行进程终止退出处理函数fini()函数,即当程序正常退出时(main()返回之后),系统会安排执行.fini 中的代码。

.fini

该section保存着进程终止代码指令。因此,当一个程序正常退出时,系统安排执行这个section的中的代码。

.init

该section保存着可执行指令,它构成了进程的初始化代码。因此,当一个程序开始运行时,在main函数被调用之前(C语言称为main),系统安排执行这个section的中的代码。

.init和.fini sections的存在有着特别的目的。假如一个函数放到.init section,在main函数执行前系统就会执行它。同理,假如一个函数放到.fini section,在main函数返回后该函数就会执行。该特性被C++编译器使用,完成全局的构造和析构函数功能。

当ELF可执行文件被执行,系统将在把控制权交给可执行文件前装载所以相关的共享object文件。构造正确的.init和.fini sections,构造函数和析构函数将以正确的次序被调用。

以上是关于编译链接实战(12)crt1.o, crti.o, crtbegin.o, crtend.o, crtn.o是什么东西的主要内容,如果未能解决你的问题,请参考以下文章

GCC详细模式输出说明

编译问题:找不到crt1.o

交叉编译遇到bin/ld: cannot find crt1.o: No such file or directory问题解决

交叉编译遇到bin/ld: cannot find crt1.o: No such file or directory问题解决

Linux下 gcc编译提示错误,,在函数_start中 main 未定义的引用

操作系统实验2:fork()系统调用