【RISC-V】从C到可执行文件分析链接重定位的过程

代码testlinker.c

cpp 复制代码
int a = 5;

int foo(void){
    return a;
}

int main(void){
    foo(); 
}

运行命令,生成中间文件

bash 复制代码
riscv64-linux-gnu-gcc testlinker.c -o testlinker --save-temps -mno-relax

--save-temps:保留所有中间文件。

-mno-relax:关闭链接器松弛优化

  • .c:高级语言文件

  • .i:预处理文件。

  • .s:汇编文件

  • .o:可重定位文件

  • 无后缀:可执行文件

查看汇编后还没链接的重定位文件

复制代码
riscv64-linux-gnu-objdump -d -r testlinker.o

以下这几行就是需要链接器重定位的地方,可以看到此时全局变量 a 的地址是"未知"的,只能留一个占位符(通常是0x0),需要在重定位中填入修正值

如a: R_RISCV_PCREL_LO12_I .L0:表示在地址偏移 a处有一个 重定位项(relocation entry) ,类型是 R_RISCV_PCREL_LO12_I,其目标符号是 .L0

重定位修正值(relocation addend / relocation offset)

在链接阶段,链接器需要写入到目标指令或数据中的具体数值,用于修正该位置的占位值(通常是 0),使其在最终可执行文件中能正确引用符号(如变量、函数)的实际地址。

修正值的计算公式取决于类型:

如a是R_RISCV_PCREL_HI20类型的,修正值=S+A-P,其中:

  • S:链接地址,被引用符号(如 a)在最终可执行文件的链接地址
  • A:重定位项中携带的附加常量(addend),在某些情况下要考虑对齐用于调整对齐
  • P:当前重定位发生处(即 auipc 指令)的 运行时地址(运行到重定位发生处该指令PC的值)。

先通过查看程序反汇编查询P,可以看到auipc指令时P=0x602(PS:这是基于人的视角从可执行文件倒推,实际链接器在连接的时候会直接根据S、A、P计算出修正值,填入重定位值)

复制代码
riscv64-linux-gnu-objdump -d testlinker

查看符号表,查看全局变量a在哪被定义

复制代码
riscv64-linux-gnu-readelf -s testlinker

可以看到链接地址S为2008,不用对齐,A=0

所以offset = S + A - P = 0x1A06,所以链接器要填入的重定位的值就是0x1A06。

相关推荐
Logic1011 小时前
C语言/数据结构数组题解:数字列表加一(Plus One)——进位处理与数组扩展
c语言·数据结构·模拟·数组·时间复杂度·算法题·进位
Escalating_xu1 小时前
【C语言常见概念】从第一行代码到字符串结束标志:一次打通编译、main、ASCII、转义字符与注释
c语言·c++
DevRay1 小时前
Java 21虚拟线程深度实战:告别线程池焦虑,百万并发吞吐量直接翻倍(原理+代码+避坑)
java·开发语言
Navigator_Z1 小时前
LeetCode //C - 1250. Check If It Is a Good Array
c语言·算法·leetcode
free-elcmacom1 小时前
C++学习<1>程序分区
开发语言·c++
醉颜凉2 小时前
Java 必看:如何彻底避免 HashMap 多线程死循环问题?
java·开发语言
默 语2 小时前
Java新手入门:从零开始安装JDK并配置环境变量
java·开发语言·python·mysql·group by·1024程序员节·数据去重
Brilliantwxx2 小时前
【STM32】 I2C_EEPROM_test 工程(实战篇)
开发语言·stm32·单片机·嵌入式硬件·ecmascript
清水白石0082 小时前
Python 异步编程深度解析:Cancellation 到底是异常还是控制信号?从 asyncio 取消机制到企业级事务设计最佳实践
开发语言·python
kolyle2 小时前
万级 QPS 下的 Token 分发系统架构:从 0 到 1 跑通 AI 时代的“水电煤“
开发语言·人工智能·系统架构·token·qps·极智词元·大模型私有化部署