在静态链接多个目标文件生成可执行文件的时候,需要在链接处理中对需要重定位表内的地址进行修正,这样保证在运行时候,程序能按照目标指令正确的执行。
但是,由于在动态链接的时候,要实现代码段的共享,那么代码段的相关虚拟地址,就不能简单的通过,重定位来修改相关的虚拟地址,因为在每个程序共享该段的时候,其地址都可能改变。这就需要使用与虚拟地址无关的代码。也就是在代码执行的时候,能使用相对地址来实现地址无关,但是这在代码指令中,是很容易实现的,因为指令本身都支持相对地址调用(例如call)。在代码中使用的数据地址,就没有相关的指令支持了。
共享模块的地址引用分类:
1.模块内函数调用,地址的引用,(内部函数调用可以使用相对地址来实现,汇编指令本身支持)
2.模块内数据引用,静态变量,全局变量引用。(可以通过数据段与当前指令的偏移来实现,即获取当前指令地址加上相对地址偏移来实现)
3.模块外部函数调用。(同理使用一个got来记录函数地址)
4.模块外部数据引用,全局变量引用。(程序通过在数据段建立一个全局偏移表(got),当程序需要的时候,通过查got表最后获取变量地址)
平常使用的动态库的编译选项-fPIC 主要指示编译器产生代码地址无关,这样就可以供多个模块共享,否则只有-share选项,则只能供一个程序共享
**全局变量共享库编译过程:如果在编译一个share库,这时候里面的全局变量都会被当做模块外部数据引用,这时候,如果有其它可执行来装载该share的时候,存在该全局变量,就将share内个got指向该执行文件的全局变量副本,否则,还是指向原来的share库内的副本
代码段的地址相关性可以通过上面的4种方式进行解决,那么数据段由于每个程序都有个副本,所以可以直接通过重定位表来修改
**为了提高动态链接程序运行效率,并没有在动态链接的时候,就将所有的地址全部指定了,而是通过一个pLT的技术来实现懒加载,其基本思想就是在模块间调用函数的时候,在got表中保存的是一个名字解析的相关函数,那么在第一次调用的时候,实际上去调用的相关链接函数来查找对应模块内函数的地址,那么在找到后就把该函数地址写到got表中,那么以后就会直接跳转到对应函数去执行。
可执行通过.interp段来启动动态链接器,然后在将控制权转交给用户程序main
动态链接将程序的所有符号和自身的符号都加入到全局符号表内。
问题:
在一个可执行文件,它的最开始的执行点在哪里,我们是否可以通过ld来指定,还有就是例如面向对象的语言,像c++这种函数的构造函数,我们是通过ld指定来怎么执行的??
elf目标文件中的section段用于linker处理的,而segment用于映射到进程空间内
阅读(1028) | 评论(0) | 转发(0) |