1. ELF重定位概念解析
在Linux系统开发中,理解ELF(Executable and Linkable Format)文件的重定位机制是掌握程序链接与加载过程的关键。重定位本质上是一种地址修正机制,用于解决编译时无法确定的符号引用问题。当我们在C代码中调用外部函数或访问全局变量时,编译器会生成相应的重定位条目,由链接器或动态链接器在适当的时候进行地址修正。
举个例子,假设我们有一个简单的C程序调用了printf函数:
c复制#include <stdio.h>
int main() {
printf("Hello World\n");
return 0;
}
编译生成目标文件时,编译器并不知道printf函数最终会被加载到内存的哪个位置,因此会在目标文件中留下一个重定位条目,指示链接器后续需要修正这个函数调用的地址。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 重定位的核心类型与原理
2.1 静态重定位与动态重定位
静态重定位发生在链接阶段,由静态链接器(如ld)完成。当多个目标文件合并成一个可执行文件时,链接器会解析所有符号引用,并根据最终的内存布局修正地址。这种重定位信息最终会被写入可执行文件的.rel.text和.rel.data段。
动态重定位则发生在程序加载或运行时,由动态链接器(如ld-linux.so)处理。共享库(如libc.so)中的代码需要能够在不同进程的不同地址空间加载,因此需要在加载时或运行时进行地址修正。这类信息通常存储在.rel.plt和.rel.dyn段。
2.2 常见重定位类型详解
在x86_64架构下,常见的重定位类型包括:
- R_X86_64_PC32:32位PC相对地址重定位
- R_X86_64_64:64位绝对地址重定位
- R_X86_64_GOTPCREL:相对于GOT(Global Offset Table)的PC相对访问
- R_X86_64_PLT32:PLT(Procedure Linkage Table)条目相关的重定位
每种重定位类型都有特定的计算方式。以R_X86_64_PC32为例,其修正公式为:
code复制S + A - P
其中:
- S是符号的实际地址
- A是重定位条目中存储的加数(addend)
- P是要被修正的位置的地址
