You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

代码重定位后GDB添加符号及断点地址计算疑问

U-Boot重定位后调试的地址计算问题

我从开机阶段就开始单步调试U-Boot执行流程。U-Boot初始启动时会完成自重重定位,本次调试中重定位地址(relocaddr)为0x3bf53000。我通过以下操作实现了重定位后的单步调试:

>>> p /x ((struct global_data)*0x3bb4eda0)->relocaddr
$1 = 0x3bf53000
>>> add-symbol-file u-boot 0x3bf53000
add symbol table from file "u-boot" at
    .text_addr = 0x3bf53000
(y or n) y
Reading symbols from u-boot...
>>> b board_init_r
Breakpoint 4 at 0x9ab54: board_init_r. (2 locations)
>>> info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep n   0x00000000000825f8 <relocate_code+20>
    breakpoint already hit 1 time
2       breakpoint     keep y   <MULTIPLE>
2.1                         y   0x000000000009ab58 <board_init_r+4>
2.2                         y   0x000000003bf6db54 in board_init_r at common/board_r.c:797

查看二进制文件时,符号地址如下:

naveen@workstation:~/.repos/src/arm64/u-boot$ readelf -s u-boot | grep board_init_r
  5162: 000000000009ab54   132 FUNC    GLOBAL DEFAULT    3 board_init_r

我疑惑为何不能直接用 0x3bf53000(relocaddr) + 0x9ab54(偏移量) = 0x3BFEDB54 设置断点?而使用add-symbol-file u-boot 0x3bf53000命令后,GDB将断点设置在0x3bf6db54,两者相差0x80000。该值恰好是U-Boot的原始加载地址,因此我猜测0x9ab54是绝对加载地址,需减去0x80000后再加relocaddr才能得到正确的断点地址。我的理解是否正确?若正确,能否提供readelf或类似命令来验证该逻辑?

另外,我执行以下命令后发现同一地址0x80000有4个条目,而非预期仅_start:

naveen@workstation:~/.repos/src/arm64/u-boot$ readelf -s u-boot  | grep 0000000000080000
     1: 0000000000080000     0 SECTION LOCAL  DEFAULT    1
    26: 0000000000080000     0 NOTYPE  LOCAL  DEFAULT    1 $x
  5419: 0000000000080000     0 NOTYPE  GLOBAL DEFAULT    1 _start
  6138: 0000000000080000     0 OBJECT  GLOBAL DEFAULT    1 __image_copy_start

你的理解完全正确

U-Boot编译时的链接地址(原始加载地址)是0x80000,readelf输出的符号地址是基于这个链接地址的绝对地址,而非镜像起始的偏移量。正确的重定位后地址计算公式为:
重定位后地址 = relocaddr + (符号链接地址 - 链接基地址)
对应到你的场景就是:
0x3bf53000 + (0x9ab54 - 0x80000) = 0x3bf53000 + 0x1ab54 = 0x3bf6db54
这和GDB通过add-symbol-file设置的断点地址完全一致。

验证方法

可以通过以下命令确认链接基地址和符号偏移:

  1. 查看U-Boot的链接基地址
    使用readelf查看镜像程序头,确认加载基地址:

    readelf -l u-boot | grep -A5 LOAD
    

    输出中VirtAddr列的第一个值就是链接时的基地址(此处应为0x80000)。

  2. 计算符号相对于链接基地址的偏移
    直接用符号地址减去链接基地址,比如board_init_r的偏移为0x9ab54 - 0x80000 = 0x1ab54,加上relocaddr即可得到正确的重定位后地址。

关于0x80000多个条目的说明

地址0x80000对应多个条目是正常现象:

  • SECTION条目:表示第1个段(通常是.text段)的起始地址为0x80000。
  • $x:链接器生成的局部符号,标记代码段起始位置。
  • _start:U-Boot的入口点,定义在代码起始处。
  • __image_copy_start:U-Boot镜像复制的起始标记,由链接脚本定义,和入口点地址一致。
    这些符号都指向镜像的起始地址,因此地址相同属于正常情况。

内容的提问来源于stack exchange,提问作者InsaneCoder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 21:35:36