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

相关推荐
爱编码的小八嘎1 天前
第3章 Windows运行机理-3.1 内核分析(2)
c语言
xuzhiqiang07241 天前
Java进阶之路,Java程序员职业发展规划
java·开发语言
MediaTea1 天前
Python:生成器表达式详解
开发语言·python
v_for_van1 天前
力扣刷题记录7(无算法背景,纯C语言)
c语言·算法·leetcode
overmind1 天前
oeasy Python 115 列表弹栈用pop删除指定索引
开发语言·python
白太岁1 天前
通信:(3) 高并发网络通信:epoll + 边沿触发 + 非阻塞 IO + tcp
c语言·网络·c++·网络协议·tcp/ip
Never_Satisfied1 天前
在c#中,使用windows自带功能将文件夹打包为ZIP
开发语言·windows·c#
hnxaoli1 天前
win10程序(十六)通达信参数清洗器
开发语言·python·小程序·股票·炒股
电饭叔1 天前
文本为 “ok”、前景色为白色、背景色为红色,且点击后触发 processOK 回调函数的 tkinter 按钮
开发语言·python