【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。

相关推荐
Dlrb12119 小时前
C语言-指针三
c语言·算法·指针·const·命令行参数
kkeeper~9 小时前
0基础C语言积跬步之深入理解指针(5下)
c语言·开发语言
一直不明飞行9 小时前
Java的equals(),hashCode()应该在什么时候重写
java·开发语言·jvm
盲敲代码的阿豪9 小时前
Python 入门基础教程(爬虫前置版)
开发语言·爬虫·python
basketball61610 小时前
C++ 构造函数完全指南:从入门到进阶
java·开发语言·c++
互联科技报10 小时前
2026超融合选型:Top5品牌与市场格局解读
开发语言·perl
weixin1997010801610 小时前
[特殊字符] 智能数据采集:数字化转型的“数据石油勘探队”(附Python实战源码)
开发语言·python
想唱rap10 小时前
IO多路转接之poll
服务器·开发语言·数据库·c++
@杰克成11 小时前
Java学习30
java·开发语言·学习
三品吉他手会点灯11 小时前
C语言学习笔记 - 40.数据类型 - scanf函数的编程规范与非法输入处理
c语言·开发语言·笔记·学习