首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

程序运行流程——链接、装载及执行 (3)

程序运行流程——链接、装载及执行 (3)

我们知道,在Linux下,动态链接器ld.so实际上也是一个共享对象,操作系统同样通过映射的方式将它加载到进程的地址空间中。操作系统在加载完动态链接器之后,就将控制权交给动态链接器。动态链接器入口地址即是自举代码的入口。动态链接器启动后,它的自举代码即开始执行。自举代码首先会找到它自己的GOT(全局偏移表,记录每个段的偏移位置)。而GOT的第一个入口保存的就是“.dynamic”段的偏移地址,由此找到动态链接器本身的“.dynamic”段。通过“.dynamic”段中的信息,自举代码便可以获得动态链接器本身的重定位表和符号表等,从而得到动态链接器本身的重定位入口,然后将它们重定位。完成自举后,就可以自由地调用各种函数和全局变量。

2,装载共享对象

完成自举后,动态链接器将可执行文件和链接器本身的符号表都合并到一个符号表当中,称之为“全局符号表”。然后链接器开始寻找可执行文件所依赖的共享对象:从“.dynamic”段中找到DT_NEEDED类型,它所指出的就是可执行文件所依赖的共享对象。由此,动态链接器可以列出可执行文件所依赖的所有共享对象,并将这些共享对象的名字放入到一个装载集合中。然后链接器开始从集合中取出一个所需要的共享对象的名字,找到相应的文件后打开该文件,读取相应的ELF文件头和“.dynamic”,然后将它相应的代码段和数据段映射到进程空间中。如果这个ELF共享对象还依赖于其他共享对象,那么将依赖的共享对象的名字放到装载集合中。如此循环,直到所有依赖的共享对象都被装载完成为止。

当一个新的共享对象被装载进来的时候,它的符号表会被合并到全局符号表中。所以当所有的共享对象都被装载进来的时候,全局符号表里面将包含动态链接器所需要的所有符号。

3,重定位和初始化

当上述两步完成以后,动态链接器开始重新遍历可执行文件和每个共享对象的重定位表,将表中每个需要重定位的位置进行修正,原理同前。

重定位完成以后,如果某个共享对象有“.init”段,那么动态链接器会执行“.init”段中的代码,用以实现共享对象特有的初始化过程。

此时,所有的共享对象都已经装载并链接完成了,动态链接器的任务也到此结束。同时装载链接部分也将告一段落!接下来便是程序的执行了。。。




执行部分
对于写过c程序的人来说,一个公认的事实是:程序是从main函数开始的。然而,真的是
这样吗?其实不然,在程序执行到main函数之前,很多事情已经由入口函数(入口点)完成了。接下来将通过一个Linux下的可执行文件p来说明它的执行过程。

Unix> ./p
因为p不是一个内置的shell命令,所以shell会认为p是一个可执行文件,通过调用某个驻留在存储器中称为“加载器”的操作系统代码来为我们运行之。装载部分已经在上述部分详细描述了。装载完成后,控制权跳转到程序的入口点,也就是符号_start的地址,在_start地址处的启动代码如下



[cpp] view plain copy




首先从.init和.text节中调用初始化例程后,启动代码调用应用程序main程序,执行我们的c程序主体。在应用程序返回后,启动代码调用atexit注册的函数,然后调用_exit结束进程,将控制返回给操作系统。

一个典型的程序的运行步骤大致如下:

1,操作系统创建进程(装载了),将控制权交给程序的入口,即运行库的入口函数。

2,入口函数对运行库和程序运行环境进行初始化,包括堆、I/O、线程、全局变量构造等等。

3,入口函数在完成这些初始化之后,调用main函数,正式开始执行程序的主体部分。

4,main函数执行完成后,返回到入口函数,入口函数进行清理工作,包括全局变量析构、堆销毁、关闭I/O等,然后进行系统调用来结束进程。

Hello程序的执行

    前面简单描述了系统的硬件组成和操作,现在开始介绍当我们运行示例程序时到底发生了些什么。在这里我们必须省略很多细节稍后再做补充,但是从现在起我们将很满意这种整体上的描述。

    初始时,外壳程序执行它的指令,等待我们输入一个命令。当我们在键盘上输入字符串“./hello”后,外壳程序将字符逐一读入寄存器,再把它存放到存储器中,如图1-5所示。
当我们在键盘上敲回车键时,外壳程序就知道我们已经结束了命令的输入。然后外壳执行一系列指令来加载可执行的hello文件,将hello目标文件中的代码和数据从磁盘复制到主存。数据包括最终会被输出的字符串“hello, world/n”。

一旦目标文件hello中的代码和数据被加载到主存,处理器就开始执行hello程序的main程序中的机器语言指令。这些指令将“hello, world/n”字符串中的字节从主存复制到寄存器文件,再从寄存器文件中复制到显示设备,最终显示在屏幕上。这个步骤如图1-7所示。



继承事业,薪火相传
返回列表