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开始的内存,所以指令的实际地址和链接时的虚拟地址对应关系是:
标签/指令 链接虚拟地址 实际加载地址 start0x20 0x0 mov r1, #20x24 0x4 add r2, r1, r00x28 0x8 stop0x2C 0xC - 第三步: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
相关产品推荐
相关产品推荐

