Take the 2-minute tour ×
Electrical Engineering Stack Exchange is a question and answer site for electronics and electrical engineering professionals, students, and enthusiasts. It's 100% free, no registration required.

I'm trying to write as tiny code as possible to extract the firmware of Infineon's XMC4500 microcontroller.

The code must fit into a 30 byte buffer which allows me to have 15 machine instructions using Thumb 16-bit instruction set.

Starting with C my attempt is to dump flash memory through a single GPIO pin (see original question) following this nifty trick.

Basically what I'm doing is:

  1. Setup the GPIO pin directions to output
  2. Blink LED1 (pin 1.1) with a clock (SPI serial clock)
  3. Blink LED2 (pin 1.0) with data bits (SPI MOSI)
  4. Sniff pins with a logic analyzer

EDIT:

  1. UPDATE C CODE BLOCK
  2. ADD ASSEMBLY CODE BLOCK
#include "XMC4500.h"

void main() {
  // start dumping at memory address 0x00000000
  unsigned int* p = (uint32_t *)(0x0u);

  // configure port1 output (push-pull)
  PORT1->IOCR0 = 0x8080u;

  for(;;) {
    int i = 32;

    int data = *(p++);

    do {
      // clock low
      PORT1->OUT = 0x0;

      // clock high with data bits
      PORT1->OUT = 0x2u | data;

      data >>= 1;

    } while (--i > 0);
  }
}
main:
    ; PORT1->IOCR0 = 0x8080UL
    ldr r1, =0x48028100 ; load port1 base address to R1
    movw r2, #0x8080 ; move 0x8080 to R2
    str r2, [r1, #0x10]

main_1:
    ; start copying at address 0x00000000
    ; R12 is known to be zeroed
    ldr.w r2, [r12], #0x4 ; int data = *(p++)
    movs r3, #32 ; int i = 32

main_2:
    ; PORT1->OUT = 0x0
    ; clock low
    ; R12 is known to be zeroed
    str r12, [r1]

    ; PORT1->OUT = 0x2 | data
    ; clock high with data bits
    orr r4, r2, #0x2
    str r4, [r1]

    asrs r2, r2, #0x1 ; data >>= 1

    subs r3, r3, #0x1 ; i--
    bne.n main_2 ; while (--i > 0)
    b.n main_1 ; while(true)

However code size is still too big to meet my requirements.

Is there anything I can do to further shrink down my code? Anything that can be optimized or left out?

share|improve this question
    
I don't think this is realistically possible, but I'll try to answer it. Edit: Could you post what the assembler made out of this? –  Dzarda Jun 10 at 22:09
8  
While it might be useful to talk about this conceptually in C, you're almost certainly going to have to do the final optimization directly in assembly code. –  Dave Tweed Jun 10 at 22:30
    
You have lots of branching in there that you don't seem to need. "If the bit is one, send one, and if it's zero, send zero" seems like you should be able to streamline it. –  Scott Seidman Jun 10 at 22:36
    
If all else fails, try self-modifying code tricks. –  Kaz Jun 11 at 0:13
    
@Dzarda Please find the generated assembly above. –  user3696425 Jun 16 at 19:36
show 2 more comments

2 Answers 2

up vote 4 down vote accepted

I'm not used to program for ARM processors and don't know which compiler you use, so maybe the proposed changes does nothing at all, but hey, at least let's try!

1-Inline your functions:

A good compiler should already inline a function if optimizations are well set, but it's worth to inline it so you remove the call's and ret's

2-Avoid branching:

In some architectures an IF can be translated in: load, test, branch, three instructions, if you can do it without branching it can use less instructions.

So, the proposed code is:

    int main() 
    {
      // start dumping at memory address 0x08000000
      unsigned int *p;
      int i;

      p = (uint32_t *)(0x08000000u);

      // configure pin 1.0 and pin 1.1 as output (push-pull)
      PORT1->IOCR0 = 0x8080UL;

      do
      {
        for (i = 0; i < 32; i++)
        {
          // set pin 1.1 to low (SPI clock)
          PORT1->OUT &= (~0x2UL);
          PORT1->OUT = (PORT1->OUT & 0xFFFE) | (data & 0x01)
          PORT1->OUT |= 0x2UL;
          data >>= 1;
        }

      }while(p++)
    }

Give it a try and comment the results.

share|improve this answer
    
Good starting point! Managed to shrank down code size to 44 bytes. Now I need to dig into the generated assembly (see code block above) to improve code size even more. –  user3696425 Jun 16 at 19:49
add comment

This assumes your 32-byte program is the only code available on the chip. No external calls are allowed.


One worry with your C code would be the inclusion and usage of the "XMC4500.h" header. Even though you're only using the "PORT1" structure so that the rest would/will get optimized out, I still think you can get more efficient GPIO-register-access than that.

Second, by your absence of information about the "project settings" I assume you haven't taken any steps to force your linker to squeeze your code to a specific location, to omit the interrupt table, initialization code, and so on. You may want to have a look here. Basically what it say, is that by modifying the .ld/.lds files you can force the linker to place specific sections of code at specific addresses.
Such script could look like this:

SECTIONS {
        . = YOUR_DESIRED_ADDRESS; 
        .text : { * (.text); }
}

I will edit the answer as new ideas come.

share|improve this answer
    
1. My program is the only code on the chip. 2. I'm fine with my header file, no need to worry about it. 3. Section merging and placement is all fine, too. –  user3696425 Jun 16 at 19:44
    
Just a random thought, why not merge these two adds? and.w r4, r2, #0x1, add.w r4, r4, #0xFF00 EDIT: Sorry, my bad (and & add) –  Dzarda Jun 16 at 20:57
    
Sorry mate, this requires some ARM Assembly guru, not me. But I suspect you may be able to chop off 2 maybe 4 bytes, you're not fitting to 32 bytes... –  Dzarda Jun 16 at 21:07
    
No worries. Managed to optimize code size to 36 bytes (see updated code blocks above). Three more instructions (6 bytes) to go and I'm fine :-) –  user3696425 Jun 17 at 7:01
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.