3

I have a system with an MPC8548 processor. My job is to send a second (external) program to the running firmware and execute it.

I have a cross compiler set up to build the base firmware and the external code.

I was able to send a separate program in runtime (I'm not sure if it's correct, but it seems to be working). Here's how I did it: in the original firmware I made room for the external code by inserting a lot of nop instructions starting at a specific memory address in the .text section. After that, in runtime, I copied the received external code (the compiled code using gcc, the .o file) to that memory address, using memcpy. Then in the original firmware I made a function pointer, pointing to that memory location and called it.

This is the external, simple code:

int external_main(void)
{
    int x = 11;
    return x;
}

And this is how I called it in the original firmware:

int (*extFuncPtr)(void);
extFuncPtr = &external_start;
int x = extFuncPtr();

external_start is specified in the linker scrip's .text section (it is the starting address of the nop instructions), and in the code declared as extern unsigned char external_start; I've printed out that memory region and the external code is there and it runs successfully (if I download some garbage there, it crashes).

My problem is, that I cannot get any return data from the external code. The value of x will be garbage. I tried passing an int* as function parameter, but it's still empty. I also tried writing something on a fix address (in the external code), and reading the same address in the firmware, but that didn't work either.

My question is that is it possible to get any data from the external code? I'm probably doing something wrong, or missing something.

Are there other possibilities to solve this problem?

EDIT 1 This is the generated assembly of the external code (calling objdump):

00000000 <external_main>:
0:  94 21 ff e0     stwu    r1,-32(r1)
4:  93 e1 00 1c     stw     r31,28(r1)
8:  7c 3f 0b 78     mr      r31,r1
c:  39 20 00 0b     li      r9,11
10: 91 3f 00 08     stw     r9,8(r31)
14: 81 3f 00 08     lwz     r9,8(r31)
18: 7d 23 4b 78     mr      r3,r9
1c: 39 7f 00 20     addi    r11,r31,32
20: 83 eb ff fc     lwz     r31,-4(r11)
24: 7d 61 5b 78     mr      r1,r11
28: 4e 80 00 20     blr

If I put that external_main function in the firmware, it generates the same instructions. And when I call it, it look like this:

   6dbdc:   4b ff 74 b5     bl      65090 <external_main>
   6dbe0:   90 7f 00 3c     stw     r3,60(r31)

And this is the generated instructions of the function pointer part:

   6dbb8:   3d 20 00 15     lis     r9,21
   6dbbc:   39 29 18 ec     addi    r9,r9,6380
   6dbc0:   91 3f 00 34     stw     r9,52(r31)
   6dbc4:   81 3f 00 34     lwz     r9,52(r31)
   6dbc8:   7d 29 03 a6     mtctr   r9
   6dbcc:   4e 80 04 21     bctrl
   6dbd0:   90 7f 00 38     stw     r3,56(r31)

EDIT 2

So I've tried a lot of things to see what the problem might be, including downloading the whole main firmware as the external program (aka injecting the firmware into the firmware in runtime). I called a function which returns a number and it worked. So I started clearing out the secondary firmware (throwing out everything unnecessary), constantly checking if it is still working or not. And it worked until the binary size became less than 16 Kilobytes.

When the external program's size is less then 16 KB, it just doesn't work (can't get any return values), but when it's 16 or higher, it works. It returns values, also if I pass a pointer to an array as input parameter (allocated in the base firmware) and populate it in the external code, when it returns the array will be there, populated.

Don't know why this happens, but it works. The external code won't be smaller than 16 KB anyway, so, it's a win in my book. If anyone has some idea why it behaves like this, I'll be glad to hear that.

Zoltán
  • 678
  • 4
  • 15
  • 1
    Calling conventions are probably mismatched. You should definitely take a look at the relevant piece of generated assembly and possibly add it to the question. Cannot say much without seeing it. The question is too broad. – Marco Bonelli Oct 03 '19 at 08:26
  • Yes, you're right. The calling conventions are different, I already check that, but don't know how to do it right. I've modified the question. If you need something, let me know – Zoltán Oct 03 '19 at 08:49
  • I've also tried branching to the external code with an assembly command: `asm("bla 0x15186c");` but with this I have the same issue: how to get the return value. (I've never used assembly before) – Zoltán Oct 03 '19 at 09:02

0 Answers0