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

ARM汇编编程:arm-none-eabi-ld -Ttext=0x20作用及PC地址疑问

关于ARM汇编链接地址与QEMU中PC值不符的疑问解答

先明确你的两个核心问题:-Ttext=0x20的作用,以及为什么QEMU里PC是0x0C。咱们一步步拆解:


1. arm-none-eabi-ld -Ttext=0x20到底做了什么?

这是给链接器传递的代码段地址指定参数,作用分3步理解:

  • 第一步:告诉链接器,把你的程序中所有属于.text段(也就是汇编里的代码指令)的内容,都放在虚拟地址0x20开始的位置
  • 第二步:链接器会基于这个起始地址,给你代码里的所有标签(比如start、stop)计算最终的虚拟地址:
    • start是第一条指令,所以地址是0x20
    • 每条ARM指令占4字节,3条指令后到stop,就是0x20 + 4*3 = 0x2C,这和你用arm-none-eabi-nm看到的结果完全一致
  • 第三步:这个地址是程序预期在目标硬件上运行的内存地址——也就是说,链接器默认你的程序会被加载到内存的0x20位置,然后从这里开始执行

2. 为什么QEMU里的PC是0x0C,而不是预期的0x2C?

问题出在链接地址和实际加载地址不匹配,具体步骤:

  • 第一步:QEMU运行ARM程序时,默认会把ELF文件的代码段加载到默认的内存起始地址(通常是0x0),而不是你链接时指定的0x20——除非你手动告诉QEMU要按照ELF指定的地址加载
  • 第二步:你的代码实际被加载到了0x0开始的内存,所以指令的实际地址和链接时的虚拟地址对应关系是:
    标签/指令链接虚拟地址实际加载地址
    start0x200x0
    mov r1, #20x240x4
    add r2, r1, r00x280x8
    stop0x2C0xC
  • 第三步:ARM CPU的复位启动逻辑是从0x0开始执行(QEMU模拟的ARM机器默认复位向量是0x0),所以程序会从0x0的start指令开始跑
  • 第四步:从你的寄存器信息来看,R0=5(第一条指令执行完成)、R2=0x11(5+12=17,说明add指令已经执行),此时程序正要执行stop标签的b stop指令,这条指令的实际加载地址是0xC,所以PC寄存器的值就是0xC(ARM架构中PC在调试时通常指向当前正要执行的指令地址,核心原因还是实际加载地址和链接地址不匹配)

验证与解决思路(可选)

如果你想让QEMU按照你指定的0x20地址加载代码,可以试试用qemu-system-arm运行时指定机器类型和内核参数,确保链接地址和加载地址一致:

qemu-system-arm -M versatilepb -kernel add.elf -append "console=ttyAMA0" -nographic

这样PC就会和你用nm看到的标签地址对应上了


补充你的相关代码与调试信息

汇编代码

start: mov r0, #5
mov r1, #2
add r2, r1, r0
stop: b stop

编译链接命令

arm-none-eabi-as add.s -o add.o
arm-none-eabi-ld -Ttext=0x20 -o add.elf

arm-none-eabi-nm -n add.elf输出

U _start
00000020 t start
0000002c t stop

QEMU调试寄存器信息

R00=00000005 R01=0000000c R02=00000011 R03=00000000
R04=00000000 R05=00000000 R06=00000000 R07=00000000
R08=00000000 R09=00000000 R10=00000000 R11=00000000
R12=00000000 R13=00000000 R14=00000000 R15=0000000c

内容的提问来源于stack exchange,提问作者Paulson Raja L

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 16:32:44