Skip to content

Address spaces

This page is short, and it has cost more hours than any other single topic in the project. Read it before converting an address.

The image loads twice

osos-dec.dfu is not loaded at one base. The first 0xB65C bytes stay in the SRAM window at 0x22000000; everything past that runs from DRAM at 0x08000000.

Two conventions are in use, and mixing them makes cross-references vanish:

  • project addresses -- what Ghidra shows, what the reports quote, what every FUN_xxxxxxxx is;
  • runtime addresses -- what a trace, a breakpoint or a profile reports.

For the DRAM half:

runtime = 0x08000000 + (file - 0xB65C)
project = runtime - 0x08000000 + 0xB65C + 0x22000000

The SRAM half has its own conversion, and it is not that one

The container's 0x800-byte header is not part of the runtime image -- the machine loads file[0x800:] at 0x22000000. So for the first 0xB65C bytes:

runtime_sram = project - 0x800
project      = 0x22000000 + file_offset        (header included)

Check any batch of SRAM conversions against a known pair before trusting it:

project runtime what it is
0x22000e14 0x22000614 the service dispatcher
0x22004324 0x22003b24 the idle loop's WFI

The conversion applies only to an address that came from a trace

This is the half that keeps being got wrong in the other direction. The dump's own headers, the reports, and every FUN_xxxxxxxx are already project addresses. Adding 0x800 to one of those is the same error, mirrored.

It applies to an address obtained from a running machine, and to nothing else -- branch targets included. A bl 0x22007bf4 inside a project-addressed listing is a project target; it inherits the space of the listing it appears in.

Why it is expensive

The wrong answer disassembles cleanly.

A conversion error does not announce itself. ARM disassembles at any aligned offset, so the wrong address hands back a real function with a plausible body and no error anywhere. Only a known pair catches it.

Three episodes, each convincing at the time:

  • a boot profile blamed a mov pc, lr CP15 stub for two thirds of a boot. The samples were actually at the RTXC idle loop's WFI, 0x800 away;
  • during the audio port, three functions were hooked with the SRAM formula while the track was audibly playing through them;
  • a function was "read" at project + 0x800, and produced several convinced minutes of analysis of an unrelated function's tail.

One more, about the file itself

Search osos-dec.dfu, the decrypted image. The encrypted osos.bin is still in the tree, and every string and constant search against it silently returns nothing -- which looks exactly like the code being absent rather than the file being encrypted.

Also: option filenames in the firmware are stored shifted left by one bit and un-shifted at runtime, so strings cannot see them.