我正在尝试为 MIPS Malta 板编写一些启动代码,在 QEMU 中进行仿真。
据我了解,马耳他板将 4MB 代码从闪存加载到物理 RAM 中的特定位置(0x1fc00000,即 MIPS 程序地址空间中的 0xbfc00000:MIPS32 复位中断位置)。我正在尝试生成将在此位置加载和运行的代码。
我有一个简单的汇编程序,它永远循环:
.text
_start:
b _start
当我用 GNU 汇编器组装它时,我得到一个带有 .text 部分的 ELF 文件,其中包含这段代码。用 objdump 反汇编它:
Disassembly of section .text:
00000000 <_start>:
0: 1000ffff b 0 <_start>
4: 00000000 nop
...
使用链接器脚本,我可以将 .text 部分重新定位到 0x8fc00000,此时反汇编会产生:
Disassembly of section .text:
8fc00000 <_start>:
8fc00000: 1000ffff b 8fc00000 <_start>
8fc00004: 00000000 nop
...
由于 ELF 文件包含其他不可执行的部分、ELF 标头等,因此我使用 objcopy 仅转储文本部分:
mips-freebsd-objcopy -O binary --only-section .text boot.o.ld boot.bin
但是,由于分支操作数仍然是相对的,因此生成的代码不使用绝对寻址并分支到 0x0 而不是 0x8fc00000:
% mips-freebsd-objdump -D -m mips -b binary boot.bin
boot.bin: file format binary
Disassembly of section .data:
00000000 <.data>:
0: ffff0010 b 0x0
4: 00000000 nop
...
我徒劳地搜索了 objcopy 或 ld 的标志,这些标志将输出中的相对地址解析为绝对地址。有 objcopy 标志来操作节起始地址,但我相信这些只会改变输出格式中的偏移表,因此不会影响二进制输出(显然没有这样的表)。
到目前为止,我发现的唯一解决方法是在程序集源中添加 .org 指令:
.org 0x8fc00000
可以理解的是,这会产生一个以零填充的 ~2GB 文件,但会产生具有绝对寻址的代码,我可以将其删除。
有没有正确的方法来做到这一点?