重定位(relocation)是把符号引用与符号定义链接到一起的过程;比如,当程序调用一个函数时,将从当前运行的指令地址处跳转到一个新的指令地址处去执行;然而在编写程序的过程中,只需要指明所要调用的函数名(即符号引用)即可,然后,在重定位过程中,动态链接器会把函数名与函数实际所在的地址(即符号定义)联系到一起,使得程序能够知道应该跳转到哪里去;重定位文件必须知道如何修改其所包含的"节"的内容,在构建可执行文件或共享目标文件时,把节中的符号引用转换成这些符号在进程地址空间中的虚拟地址;包含这些转换信息数据的就是"重定位项"(relocation entry);重定位项的格式使用结构体Elf32_Rel/Elf64_Rel描述:struct Elf32_Rel{ Elf32_Addr r_offset; /* Address */ Elf32_Word r_info; /* Relocation type and symbol index */};struct Elf64_Rel{ Elf64_Addr r_offset; /* Address */ Elf64_Xword r_info; /* Relocation type and symbol index */};带加数的重定位项的格式使用结构体Elf32_Rela/Elf64_Rela描述:struct Elf32_Rela{ Elf32_Addr r_offset; /* Address */ Elf32_Word r_info; /* Relocation type and symbol index */ Elf32_Sword r_addend; /* Addend */};struct Elf64_Rela{ Elf64_Addr r_offset; /* Address */ Elf64_Xword r_info; /* Relocation type and symbol index */ Elf64_Sxword r_addend; /* Addend */};------字段解释------r_offset:该字段指明重定位所作用的位置;对于重定位文件来说,该值是受重定位所作用的存储单元在节中的字节偏移量;对于可执行文件或共享目标文件来说,该值是受重定位所作用的存储单元的虚拟地址;r_info:该字段指明重定位所作用的符号表索引和重定位的类型;比如,如果是一个函数需要重定位,则该字段的值就是被调函数所对应的符号表索引;如果索引值为STN_UNDEF,则未定义索引,那么重定位过程中将使用0作为符号值;重定位的类型依据处理器的不同而不同;如果一种处理器规定自己引用了一个重定位项的类型或者符号表索引,则表明这种处理器应用了ELF32_R_TYPE/ELF64_R_TYPE或ELF32_R_SYM/ELF64_R_SYM到其重定位项的r_info字段;读写r_info字段的数据:#define ELF32_R_SYM(val) ((val)>>8)#define ELF32_R_TYPE(val) ((val)&0xff)#define ELF32_R_INFO(sym,type) (((sym)<<8)+((type)&0xff))#define ELF64_R_SYM(i) ((i)>>32)#define ELF64_R_TYPE(i) ((i)&0xffffffff)#define ELF64_R_INFO(sym,type) ((((Elf64_Xword)(sym))<<32)+(type))r_addend:该字段指定了一个加数,这个加数用于计算需要重定位的域的值;一个重定位节需要引用另外两个节:符号表节和被修改节;在重定位节中,节头中的字段sh_info和sh_link分别指明了引用关系;不同的目标文件中,重定位项中的r_offset字段的含义有所不同;在重定位文件中,r_offset字段含有一个节偏移量;也就是说,重定位节本身描述的是如何修改文件中的另一个节的内容,重定位偏移量r_offset指明了另一个节中的一个存储单元的地址;在可执行文件或共享目标文件中,r_offset字段含有的是符号定义在进程地址空间中的虚拟地址;可执行文件和共享目标文件是用于运行程序,而不是构建程序,所以,对它们来说,更有用的信息是运行时的内存虚拟地址,而不是某个符号定义在文件中的位置;重定位类型(Relocation Types):重定位类型描述了如何修改被重定位域的对应位;被重定位域是一个32位的域,占用4个字节,且地址按4字节对齐;