Posts Tagged ‘recover mcu memory’

PostHeaderIcon ATmega861PA: Why the Addresses Move When the Code Grows

An image is laid out in order, and there is no padding between sections by default. Insert an instruction anywhere before the end and everything after it moves by the size of the insertion. Nothing is wrong; the addresses are simply different.

That has a consequence for anyone comparing two builds or matching a disassembly against documentation: an address is not an identity. A function at a given address in one build may be something else entirely in the next.

Where the layout comes from

The linker places sections in a fixed order and, within each, in the order the objects were supplied. Four sections are typical:

Section Content Moves when
Vectors Jump table Rarely; fixed size
Text Code Any code change before it
Data initialisers Initial values for SRAM Code size changes
Constants Tables, strings Code size changes

The first row is the only stable one. Everything after the vector table is positioned relative to the code that precedes it, which is why an address found in one build rarely means anything in another.

What this does to a comparison

Two builds of the same product, one with a bug fix, produce images that differ from the point of the change onward. A byte-wise diff reports the whole tail as different, which is useless.

The way to compare meaningfully is to compare structure rather than addresses:

  • Align on the vector table, which does not move.
  • Align on string and constant blocks, which keep their content even when their address changes.
  • Compare instruction sequences rather than byte offsets.

With those three anchors, a diff of two builds becomes a list of actual changes rather than a list of shifted bytes.

What it means for a reconstruction

A reconstruction is a description tied to addresses: “the routine at this address does that”. If the description is ever applied to a different build, the addresses are wrong and the description misleads.

The fix is to record structure alongside address. A function described as “the third handler in the table, calling the shift routine twice” survives a rebuild; one described as “the code at address 0x04A2” does not.

That is not pedantry. Products get reflashed, revisions get rebuilt, and a report that only works for one binary has a short useful life.

The array limit and what happens near it

As an image approaches the size of its array, two things occur:

Constants get pushed. Tables that were inline move to the end, because there is no room between functions. The image’s tail becomes a data region rather than code, which changes how it should be read.

Jump distances grow. Branches that were short become long, which changes instruction sizes and therefore shifts everything again. On a part where the boundary between relative and absolute jumps is near, a small addition can convert a whole region.

Both effects are visible if the image is examined near its limit, and both are invisible if it is not. Knowing which case applies sets the expectation for how much of the tail will disassemble as code.

Reading an image near its limit

  1. Read the array, verified page by page.
  2. Decode the vector table; confirm the reset target.
  3. Read forward from the target until instructions stop making sense.
  4. From that point, treat content as data and check for structure: fixed stride, printable text.
  5. Record the boundary and describe the function in structural terms.

Step 4 is the one that prevents the classic error of disassembling a constant table as code. Tables have regular stride and no valid opcodes; code has irregular structure and valid opcodes. The transition is usually obvious once it is being looked for.

Related notes

FAQ

Do addresses stay the same across builds? Only the vector table. Everything after it moves with code size.

Can a diff be done without alignment? It can be run. The output will be mostly false differences.

Why do constants end up at the end? Because the linker places them after code when there is no room inline.

Is a disassembly of the data region harmful? It produces plausible nonsense that can be mistaken for obfuscation.

Conclusion

Addresses are a property of a build, not of a program. Comparing builds needs structural anchors, and describing a program needs structural language, because the numbers change the moment anyone edits the source. Recording structure is what makes an analysis survive the next release.