Instead of trying to relocate the entire firmware and worrying about finding every code reference, our approach has been to relocate to RAM just the functions that need to be changed. Since we am targetting Canon dialog code that is called through a function pointer, the code is able to walk the GUI structures in RAM to find the pointer to the ROM routine and update it there. On the next redraw or event cycle the relocated code will be called instead and can execute our modified instructions.
reloc.c has the routines that do the copy and instruction fixup. The only instructions that are currently fixed are:
- LDR rN, [ pc, off ]
If the B or BL or target of LDR are within the relocating region, they are not touched. Otherwise the offsets are adjusted. If the 12-bit offset of the LDR is out of range the constant value is copied from ROM into RAM in a small block of fixups.
reloc() detects, but does not fixup ADD rN, pc, off instructions. For the code that I am currently targetting there are only two references that are out of range, and they related to debugging printf formats so I just NOP out the call to DebugMsg(). My plan is to fix these automatically in a newer version of the code by reserving a fixup space at the end of the allocated buffer as well.
The first proof of concept is to rewrite the portion of the DlgLiveViewApp() function that switches from 1080i HD to 480p on the HDMI port when recording is started. The code that does this is in liveview.c. Here is a video showing this in action:
There are some problems related to what appears to be a rolling shutter or timing sync issue with the 1080i output and the 30p recorded h.264 file. Occasional frames show up with a pattern like the first image on the right. Sometimes they are even worse and appear to get the YUV buffer at a very bad time. The pattern of the rolling shutter might tell us something about how Canon scans the CMOS sensor.