Linux 的内核在执行 execve()
的时候不关心目标 elf 文件是不是可以执行的,它只是通过程序头表里的描述对文件进行装载和把控制权交给 elf 的入口地址(如果没有 .interp
就是 e_entry
,如果有就是动态链接器的 e_entry
)
所以动态链接器也是可以作为可执行文件运行的,这也从一个侧面说明了共享库和可执行文件其实没有什么区别,除了文件头的标志位和拓展名有不同之外,其他都是一样的。Windos 也有一个 rundll32
工具来运行 dll 文件
ELF 动态链接器的入口在 dl-manchine.h
,普通程序的入口地址在 start.S
_start
调用 rtld.c
的 _ld_start()
函数,对 ld.so
进行重定位,完成自举,然后调用 _dl_start_final
收集一些基本的运行数值,进入 _dl_sysdep_start
进行平台相关处理,进入 _dl_main
,动态链接器的主函数先进行判断:用户的入口地址是不是动态链接器本身,如果是的话,说明动态链接器是可以被当作可执行文件在执行,这种情况下,动态链接器会解析相应的参数进行处理。随后对依赖的共享对象进行装载、符号解析和重定位等等
- 动态链接器是静态链接的,因为它不能够依赖其他共享对象
- 动态链接器是 PIC 的,这样可以简化操作,不用在自举的时候最自己重定位
- 作为一个共享库,动态链接器在装载的时候会自动选择一个合适的装载地址,即不是固定的