链接

链接是将各种代码和数据片段收集并组合成为一个单一文件的过程,这个文件可被加载到内存并执行

大致过程如下

20203219101

2022622212733

编译器驱动程序

批注 2019-07-10 093808

链接的原因

静态链接

静态链接

目标文件

可重定位目标文件

2022622212215

ELF 文件格式把各种信息,分成一个一个的 Section 保存起来

  1. .text Section,也叫作代码段或者指令段(Code Section),用来保存程序的代码和指令
  2. .data Section,也叫作数据段(Data Section),用来保存程序里面设置好的初始化数据信息
  3. .rodata:只读数据,例如字符串常量、const 的变量
  4. .bss:未初始化全局变量,运行时会置 0
  5. .strtab:字符串表、字符串常量和变量名
  6. .rel.text Secion,叫作重定位表(Relocation Table)。重定位表里,保留的是当前的文件里面未知的一些函数跳转地址,比如printf函数
  7. .symtab Section,叫作符号表(Symbol Table)。符号表保留了我们所说的当前文件里面定义的函数名称和对应地址的地址簿

符号和符号表

/* ELF符号表条目 */
typedef struct {
  int name; /* String table offset */
  int value; /* Section offset,or VM address */
  int size; /* Obiect size in bytes */
  char type:4, /* Data,func,soction,or src file name (4 bits) */
      binding:4; /* Local or global (4 bits) */
  char reserved; /* Unused */
  char section; /* Soction hoader index,ABS.UNDEF */
} Elf_Symbol;

符号解析

处理多重定义的全局符号

与静态库链接

链接器使用静态库解析引用

重定位

重定位条目

重定位符号引用

可执行目标文件

20221020152013

加载可执行目标文件

动态链接共享库

在给定的文件系统中一个库只有一个文件,所有引用该库的可执行目标文件都共享这个文件,它不会被复制到引用它的可执行文件中

在内存中,一个共享库的 .text 节(已编译程序的机器代码)的一个副本可以被不同的正在运行的进程共享

20203219214

2022622213753

多了两个 section,一个是.plt,过程链接表(Procedure Linkage Table,PLT),一个是.got.plt,全局偏移量表(Global Offset Table,GOT)

为了调用共享库里的函数,首先第一步调用PLT[x]里面的代理代码,这个代理代码会在运行的时候找真正的函数

plt[x]->got[y](发现没有地址)->plt[0]->got[2](存了一个特殊的动态链接库ld-Linux.so,他会负责找到链接的函数)->将找到的地址存回got[y]

从应用程序中加载和链接共享库

JNI

位置无关代码

可以加载而无需重定位的代码称为位置无关代码

库打桩机制