动态链接的可执行程序的加载过程

1)内核在装载完 ELF 可执行文件以后就返回到用户空间,将控制权交给程序的入口。对于不同链接形式的 ELF 可执行文件,这个程序的入口是有区别的。对于静态链接的可执行文件来说,程序的入口就是 ELF 文件头里面的 e_entry 指定的入口;对于动态链接的可执行文件来说,如果这时候把控制权交给 e_entry 指定的入口地址,那么肯定是不行的,因为可执行文件所依赖的共享库还没有被装载,也没有进行动态链接。所以对于动态链接的可执行文件,内核会分析它的动态链接器地址(在 “.interp” 段),将动态链接器映射至进程地址空间,然后把控制权交给动态链接器。
2)Linux 的 ELF 动态链接器是 Glibc 的一部分,它的源代码位于 Glibc 源码的 elf 目录下。以 mips 为例,它的实际入口地址位于 sysdeps/mips/dl-machine.h 中的 __start,由汇编实现,和平台相关。
3)__start 会调用位于 elf/rtld.c 的 _dl_start() 函数,_dl_start() 函数首先对 ld.so 进行重定位,然后调用 _dl_start_final,收集一些基本的运行数值,并进入 _dl_sysdep_start,这个函数进行一些平台相关的处理之后就进入了 _dl_main,这个是真正意义上的动态链接器的主函数,它的主要工作是对程序所依赖的共享对象进行装载、符号解析和重定位。
4)_dl_start() 函数的返回值是用户程序的 entry point,即普通程序的入口地址 __start(和上面的 __start 名称相同,但内容不同)。以 mips 为例,它的源码在 sysdeps/mips/start.S 中,它是 Glibc 的程序入口,这里的 __start 同样由汇编实现,和平台相关。__start 会依次调用 __libc_csu_init --> __libc_csu_start_main --> main (即用户定义的 main 函数) --> __libc_csu_fini --> exit,以此来完成对用户程序的执行。
 

参考资料:
1、glibc-2.28 源码
2、《程序员的自我修养--链接、装载与库》,俞甲子,石凡,潘爱民,电子工业出版社。
3、https://blog.csdn.net/conansonic/article/details/63254223

 

猜你喜欢

转载自blog.csdn.net/choumin/article/details/113938601