u-boot ARMv8架构重定位相关汇编与链接脚本代码疑问
问题1:__rel_dyn_start符号的来源
__rel_dyn_start和对应的__rel_dyn_end是GNU链接器(ld)在链接阶段自动生成的隐式全局符号,不需要在链接脚本中显式定义:
- 你贴的链接脚本里定义了三个连续的输出段:
.rel_dyn_start、.rela.dyn、.rel_dyn_end,刚好把所有重定位表项夹在中间 - GNU ld默认会为每一个自定义输出段生成对应起止地址的符号,规则是将输出段名开头的
.替换为__作为符号前缀,这里.rel_dyn_start段的起始地址就对应__rel_dyn_start符号,.rel_dyn_end段的结束地址对应__rel_dyn_end符号,方便汇编/C代码直接引用段的边界地址。
问题2:重定位逻辑的核心解释
你的推测是对的,x9确实存储的是U-Boot实际运行地址和链接时预设地址的偏移量,这部分逻辑的细节如下:
1. cmp w1, #1027的含义
1027是ELF规范中定义的AArch64平台R_AARCH64_RELATIVE重定位类型的编号。
U-Boot的重定位表每一项是标准的AArch64 Elf64_Rela结构体,固定24字节,三个成员依次是:
r_offset(8字节):链接时计算的、需要修改重定位值的内存虚拟地址,对应代码里的x0r_info(8字节):低32位存重定位类型,高32位存关联的符号索引,对应代码里的x1,所以取低32位w1和1027比较,就是筛选出相对重定位项r_addend(8字节):重定位计算用的加数,对应代码里的x4
U-Boot的PIE(位置无关执行)编译模式下,只会生成R_AARCH64_RELATIVE类型的重定位项,其他类型的重定位要么在编译阶段就处理完成,要么不需要运行时修正,所以匹配失败就直接跳过当前项。
2. 修正操作的逻辑
当确认是相对重定位项时:
- 给x0加x9:x0是链接时的虚拟地址,加上重定位偏移x9后,得到实际运行时需要修改的物理内存地址
- 给x4加x9:x4是基于链接地址计算的加数,加上重定位偏移x9后,得到实际运行时的正确值
- 把修正后的x4写入修正后的x0指向的地址,就完成了当前重定位项的修正
循环遍历整个重定位表(直到x2等于x3),就完成了所有地址的重定位修正。
内容的提问来源于stack exchange,提问作者Chan Kim
相关产品推荐
相关产品推荐

