I'm attempting to write some boot code for a MIPS Malta board, emulated in QEMU.
As I understand it, the Malta board loads 4MB of code from flash to a specific position in physical RAM (0x1fc00000, which is 0xbfc00000 in the MIPS program address space: the MIPS32 reset interrupt location). I'm trying to produce the code that will be loaded and run at this location.
I have a simple assembly program which just loops forever:
.text
_start:
b _start
When I assemble this with the GNU assembler, I get an ELF file with a .text section containing this code. Disassembling it with objdump:
Disassembly of section .text:
00000000 <_start>:
0: 1000ffff b 0 <_start>
4: 00000000 nop
...
Using a linker script I can relocate the .text section to 0x8fc00000, at which point the disassembly yields:
Disassembly of section .text:
8fc00000 <_start>:
8fc00000: 1000ffff b 8fc00000 <_start>
8fc00004: 00000000 nop
...
Since the ELF file contains other sections, ELF headers, etc, which are non-executable, I use objcopy to dump only the text section:
mips-freebsd-objcopy -O binary --only-section .text boot.o.ld boot.bin
However, since the branch operand is still relative, the resultant code does not use absolute addressing and branches to 0x0 rather than 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
...
I've searched in vain for flags to objcopy or ld that would resolve relative addresses to absolute ones in the output. There are objcopy flags to manipulate section start addresses, but I believe these just alter the offset tables in the output format, and so don't affect binary output (which obviously has no such tables).
The only workaround I've found so far is to add a .org directive in the assembly source:
.org 0x8fc00000
This understandably produces a ~2GB file front-padded with zeroes, but yields code with absolute addressing which I can chop out.
Is there a correct way to do this?