main函数和启动例程(Startup Routine)

gcc编译文件的过程:gcc -v hello.c 可以看到完整的编译过程

使用gcc编译器编译C源程序时,gcc hello.c,会在当前目录中生成一个a.out的可执行文件。file a.out可以查看文件的类型

这是一个ELF的文件,executable可执行。使用-o选项可将生成的可执行文件进行重命名。gcc -o hello hello.c

而程序编译经历了 预处理 -> 编译 -> 汇编 -> 链接的过程。

预处理:cpp预处理器,gcc -E

程序的预处理不会对文件c源文件进行编译,但是会将#include的文件和程序中定义的宏展开,如图

定义了一个MAXSIZE的宏,在main函数中将宏复制给了变量a,预处理展开后,

MAXSIZE的值被100替换了。

2. 编译 gcc -S hello.i -o hello.s

文件被编译器编译成hello.s文件,文件内容为原来c程序的汇编代码,如下所示

3. 汇编 gcc -c hello.s -o hello.o; as是汇编器

通过汇编器生成目标文件hello.o,目标文件不能够通过vim编辑器打开阅读

4. 连接 ld为连接器,gcc会默认使用ld连接器进行连接,并添加了默认选项用于文件的连接

使用ld连接器连接目标程序

ld /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/crtn.o hello.o -o hello -lc -dynamic-linker /lib/ld-linux.so.2

连接器连接三个目标文件,分别是crt1.o, crti.o, crtn.o,使用file查看

发现文件crtn.o stripped,即该文件去除了全局符号表等信息,使用nm查看不到符号表。,使用readelf -a crtn.o可以查看该文件没有了哪些信息。

crti.o来之crti.S,crtn.o来之crtn.S

而crti.S和crtn.S则都来之initfini.s
 

initfini.s则来之与sysdeps/generic/initfini.c

crti和crtn就是将两个函数init和fini分别切成两截,他们的前半截放入crti,后半截放入crtn.

为什么要这么做呢?

如果有某些工作需要在main之间完成和main之后完成,那么,就可以将相应的代码放入目标文件的
.init和.fini节。在ld链接时,会按照给定的目标文件顺序,依次合并同名节。

这样就能将相应代码插入_init函数和_fini函数中,从而达到目的。

使用nm 查看crt1.o和crti.o的符号表

nm crt1.o                                                                     nm crti.o

00000000 R _IO_stdin_used                                                            U _GLOBAL_OFFSET_TABLE_

00000000 D __data_start                                                                w __gmon_start__

         U __libc_csu_fini                                                     00000000 T _fini

         U __libc_csu_init                                                     00000000 T _init

         U __libc_start_main
00000000 R _fp_hw
00000000 T _start
00000000 W data_start

               U main

        

crt1.o中出现的U main表示crt1.o文件中使用到了main,但是没有定义(U表示Undefined),函数的入口就是_start,T表示代码段(Text),_start首先做一些初始化工作(即启动例程Startup Routine),然后调用C代码中的main函数,所以函数的入口函数真正是_start,main函数是被_start调用的。

而在crt1.o中出现了一个未定义的__libc_start_main符号,在其他几个文件中也没有相应的定义,这个是在运行时做动态链接的,连接选项中指定了连接库 -lc 即需要连接libc库, -dynamic-linker /lib/ld-linux.so.2指定了动态链接的库。

猜你喜欢

转载自blog.csdn.net/qingzhuyuxian/article/details/81102360