QEMU未跳转至指定地址0xC0008000加载镜像的问题求助
我的链接脚本设置如下:
SECTIONS{ . = 0xC0008000; __text_start = .; .text : { boot/start.o *(.text) } __text_end = .; .rodata ALIGN(4) : {*(.rodata*)} .data ALIGN(4) : { *(.data) } __bss_start = .; .bss ALIGN(4) : { *(.bss) *(COMMON) } __bss_end = .; }
我指定0xC0008000作为bootloader的加载地址,希望QEMU能按这个地址加载镜像并执行,但尝试两种命令后都没达到预期:
第一种命令
qemu-system-arm \ -machine virt \ -cpu cortex-a15 \ -nographic \ -S -s \ -m 4096M \ -kernel Image \ # -device loader,file=Image,addr=0xC0008000
执行后PC从0x40000000启动,随后跳转到0x40010000处的bootloader——这符合Virt平台RAM起始地址为0x40000000的特性,但不符合我让代码在0xC0008000执行的预期。
第二种命令
qemu-system-arm \ -machine virt \ -cpu cortex-a15 \ -nographic \ -S -s \ -m 4096M \ -kernel Image \ -device loader,file=Image,addr=0xC0008000
此时镜像成功加载到0xC0008000,但0x40010000处出现重复指令,且PC始终无法跳转到0xC0008000,调试陷入困境。
问题原因
重复加载的根源:
-kernel参数是QEMU为ARM Virt平台预设的内核加载逻辑,它会自动把镜像加载到默认地址0x40010000,同时通知平台启动固件跳转到该地址执行。而你额外添加的-device loader参数又把镜像加载到了0xC0008000,导致同一镜像被加载到两个不同地址,这就是0x40010000出现重复指令的原因。PC不跳转的核心原因:Virt平台的启动流程由内置ROM固件控制,当你使用
-kernel参数时,QEMU会向固件传递“内核入口在0x40010000”的信息,固件启动后会严格按照这个地址跳转,完全忽略你通过-device loader加载到0xC0008000的镜像。
解决办法
要实现PC跳转到0xC0008000执行,需要彻底抛弃-kernel参数的默认逻辑,改用-device loader完全控制镜像加载和入口地址:
qemu-system-arm \ -machine virt \ -cpu cortex-a15 \ -nographic \ -S -s \ -m 4096M \ -device loader,file=Image,addr=0xC0008000 \ -device loader,addr=0xC0008000,cpu-num=0
- 第一个
loader设备负责把镜像加载到0xC0008000地址; - 第二个
loader设备直接设置CPU 0的初始PC为0xC0008000,绕过ROM固件的默认跳转逻辑,启动后直接执行该地址的代码。
另外需要确认:你的链接脚本中boot/start.o的入口指令确实位于0xC0008000,没有因段对齐或其他原因产生偏移。
内容的提问来源于stack exchange,提问作者Haoson Q

