浅回忆链接与装载

0x00 链接

​ 编译的前三步(预处理编译汇编)生成的代码时可重定位目标文件,并非可执行文件。经过链接后才能生成可执行文件。

​ 链接做了两件事,①解析重定位目标文件里定义和引用的符号 ②为这些符号重新分配地址,修改使用这些符号的地址。

​ 由此,我们可以将多个目标文件链接在一起且能正确工作。

​ 这两件事情,实现了编译时的静态链接,和装载时的动态链接。前者将引用的外部文件一起打包进入可执行文件,在编译时就完成了上述两件事。后者则在装载时调用链接器完成上述两件事。

​ 装载时的动态链接,仍然是解析符号,修改使用符号的地址。动态链接的好处是避免了库的重复储存和装载。但仍然不够灵活,需要在装载时确定全部符号位置

​ (位置无关代码)运行时的动态链接,则实现了运行时动态调用库。其原理是延迟绑定(c++虚函数是动态绑定)。代码中对动态链接的符号的访问,都是用的相对偏移地址,偏移到数据节(下面装载讲)里的一个表里的表项,这个表项里的值只有在第一次访问时才会被置为对应符号的地址。 这样无论库到底被映射到虚拟内存的任何地方,代码的访问都没有影响。

0x01 装载

​ 首先我们得知到可执目标文件格式(linux上的elf):

​ ①elf头:总体描述文件格式,及程序入口点

​ ②段头部表:描述有多少个段,每个段在文件中的起始位置,长度,及映射到内存的地址

​ ③init节 //实际的入口代码,运行时调用动态库init

​ ④.txt节

​ ⑤.rodata节 //③-⑤为代码段

​ ⑥.data

​ ⑦.dss //⑥⑦为数据段

​ ⑧.symbol //声明的 引用的 全局和静态符号 静态为loacl

​ ⑨.debug //-g指令生成的符号表

​ ⑩.line // -g行与指令的对应关系

​ 11.strtab

​ 12.节头部表 8-12是符号表和调试信息

​ 静态链接和装载时动态链接解析的符号就是.symbol里的,并对引用这些符号的地方修改地址。

​ 程序装载进内存后:

​ ①内核空间

​ ②用户栈

​ ③共享内存映射

​ ④堆

​ ⑤读写数据段 .bss .data //全局/静态变量

​ ⑥只读代码段 .init .text .rodata