第7课

来源:互联网 发布:2017广电禁止网络电视 编辑:程序博客网 时间:2024/06/06 14:21

一、问题

1、源文件被编译后生成目标文件,这些目标文件如何生成最终的可执行程序?


链接器的意义:链接器的主要作用是是把各个模块之间相互引用的部分处理好,使得各个模块之间能够正确的衔接。

net.o -- math.a -- logic.o -- libc.a -- init.o


2、目标文件(.o文件)的秘密

- 各个段没有具体的起始地址,只有段的大小信息

- 各个标识符没有实际地址,只有段中的相对地址

- 段和标识符的实际地址需要链接器具体确定


3、链接器的工作内容

将目标文件和库文件整合为最终的可执行程序。

- 合并各个目标文件中的段(.text .data .bss)

- 确定各个段和段中标识符的最终地址(重定位)


二、问题:main函数是第一个被调用执行的函数吗?

1、默认情况下(gcc):

- 程序加载后, _start()函数是第一个被调用执行的函数

- _start()函数准备好参数后立即调用_libc_start_main()函数

- _libc_start_main()函数初始化运行环境后调用main()函数执行

(_start()函数的入口地址就是代码段(.text)的起始地址)


2、_libc_start_main()函数的作用:

- 调用_libc_csu_init()函数(完成必要的初始化操作)

- 启动程序的第一个线程(主线程),main为线程入口

- 注册_libc_csu_fini()函数(程序运行终止时被调用)


3、程序的运行过程:

_start  -->  _libc_start_main  --> _libc_csu_init  --> _init --> _do_global_ctors_aux --> main


4、既然mian是主线程的入口,那么可以换成别的名字吗?

自定义程序入口函数

- gcc提供 -e 选项用于在链接时指定入口地址;

- 自定义入口函数时必须使用 -nostartfiles 选项进行链接


#include <stdio.h>#include <stdlib.h>int program(){    printf("D.T.Software\n");    exit(0);}

gcc -c program.c -o program.o

gcc -e program program.o -o program.out(

gcc -e program -nostartfiles program.o -o program.out(


链接选项 -nostartfiles的意义是什么?

解答:在链接的时候,不使用标准系统启动文件,比如_start()函数等,因为这些标准文件的主线程入口是main,所以要去掉,去掉之后,program函数就成了第一个被执行的函数,而不是_start()函数了。我们也可以从 objdump -S program.out的反汇编代码看到,里面没有_start()函数等。


疑问:我们自定义入口函数后,第一个函数就不是start了,那么那些运行时环境从哪里创建呢?

解答:你试试把最后的 exit(0) 换成 return 0就知道了。你会发现产生段错误 。原因就是没有start 没有注册全局清理函数, 所以不知道结束程序了。

而这个例子里面的程序逻辑非常简单 ,没有一些运行环境条件也可以运行,本质是使用了put系统调用。如果你要用这种方式做一些“功能复杂”的程序, 必死无疑,所以这就是为什么用exit 0来结束程序了。这个程序只是给大家说明程序链接和运行的机制。

这个例子的意义在于 ,在一些嵌入式程序中,程序只需要运行就好,不用像linux中那样,需要做很多的准备工作和清理工作。像单片机的start函数只需要设置堆栈就可以了,并没有做过多的初始化动作。



(版权声明:本文内容归狄泰软件所有,博主整理所得,未经博主允许不得转载。)