从程序员角度来看ELF文件

1 介绍
ELF文件是一种linux/unix上通用的可执行文件格式,其比a.out和COFF二进制格式有更多的灵活性和功能。
2 类型
三种类型:
(1)可执行文件,包含代码和数据,指定了进程的地址空间分布;
(2)可重定位文件,包含代码和数据,用于被其他的可重定位文件或者共享库文件链接使用;
(3)共享库文件,包含代码和数据,在静态链接和动态链接时,被链接工具ld使用,动态链接库一般以.so结尾。
ELF文件最有用的地方在于其内部的section结构。
3 .init 和 .fini section介绍
3.1 概述
(1)ELF系统加载一个ELF文件到内存中,需要一些段的信息来构建该进程的虚拟地址空检结构的分布,一个段包括很多的section。
(2)一个ELF文件包括由section组成的数组,数组中有一些很重要的section需要被程序员理解:.fini section,该节中包括一个进程正常退出需要执行的代码;.init section,该节包括进程开始真正执行前需要执行的代码,即main函数之前。
当一个函数被放到.init section中的时候,那么该函数将会在main函数执行前被执行;当一个函数被放置到.fini sction中的时候,那么该函数将会在main函数返回后执行。
因此,构造函数和析构函数可以在这两个节中执行。
3.2 C++中的全局构造函数和析构函数
.ctors section:保存一个程序的全局构造函数的指针数组
.dtors section:保存一个程序的全局析构函数的指针数组
crtbegin.o 启动辅助文件包含四个section:
.ctors section:有一个局部符号CTOR_LIST,指向全局构造函数指针数组的头部,在crtbegin.o文件中的该数组只有一个元素。
.dtors section:有一个局部符号DTOR_LIST,指向全局析构函数指针数组的头部,在crtbegin.o文件中的该数组只有一个元素。
.text section:只包含一个函数do_global_dtors_aux,该函数遍历__DTOR_LIST数组,并依次执行数组中的每个函数。
.fini section:只包含一个调用函数__do_global_dtors_aux的call,只有call指令,没有返回值,因为该文件的.fini节的内容是一个函数的一部分。
crtend.o 包含四个section:
.ctors section:有一个局部符号CTOR_END,指向全局构造函数指针数组的尾部,在crtbegin.o文件中的该数组只有一个元素。
.dtors section:有一个局部符号DTOR_END,指向全局析构函数指针数组的头部,在crtbegin.o文件中的该数组只有一个元素。
.text section:只包含一个函数do_global_ctors_aux,该函数遍历__CTOR_LIST数组,并依次执行数组中的每个函数。
.init section:只包含一个调用函数__do_global_ctors_aux的call,只有call指令,没有返回值,因为该文件的.init节的内容是一个函数的一部分。
crti.o:只有一个函数标签_init在.init section中,一个函数标签_fini在.fini section中。
crtn.o:只分别在.init 和 .fini section中有一个return返回指令。
GCC在链接阶段,在加载其他可重定位文件前加载crtbegin.o,在加载完其他可重定位文件后加载crtend.o,另外,GCC会将crti.o放在crtbegin.o之前,将crtn.o放在crtend.o的后边。当生成可执行文件的时候,链接器ld会收集所有可重定位文件中.ctors sections 和 .dtors sections中的内容来形成CTOR_LISTDTOR_LIST 函数指针数组。

4 动态链接和动态加载
4.1 动态链接
动态链接库文件是一个包含数据和代码的共享对象文件,在程序运行时,动态链接器将会映射动态链接库文件到进程的虚拟地址空间中,以解决进程使用的共享链接库的名字符号缺失的问题。该过程对于进程来说时透明的,无感知的。
4.2 动态加载
进程在执行过程中可以attach一个共享库文件到自己的虚拟地址空检中,然后查找自己需要的函数的地址,然后调用那个函数,当不需要该文件的时候detach该文件,该过程被称之为动态加载,其被实现为一个动态链接服务的一个接口。
在头文件

void *dlopen (const char * filename, int flag);
const char * dlerror (void);
const void * dlsym (void  handle*, const char * symbol);
int dlclose (void * handle);

参考资料:http://l4u-00.jinr.ru/usoft/WWW/www_debian.org/Documentation/elf/elf.html
未完待续……

猜你喜欢

转载自blog.csdn.net/u011414616/article/details/80813204
今日推荐