2

Is it possible to remote update or patch only certain piece of code to an embedded device (microcontroller)?

I am writing a bare metal C program on a microcontroller. Lets say I have main program which comprises of function A(), B(), C() and D() each in their own .c file. I would like to do a remote update (patching) of only B() which has its own custom section in the main program so that the address is fixed and known.

The thing that puzzles me is how do I produce an updated executable of B()? Given that it relies on standard C library or other global variables from the main program. I need to resolve all the symbols from the main program.

Would appreciate any suggestions or reference to other thread if this question has been asked before (I tried to search but couldn't find any)

Solutions:

  • from Russ Schultz: Compile the new B(), and link it with the symbol file previously generated from the main program using gcc --just-symbols option. The resultant elf will contain just B() that assumes all these other symbols are there. (I haven't tried it but this is the concept that I was looking for)
  • Compile the whole program with the new B(), and manually take only the B() part binary from the main program (because its section address and size are known). Send B() binary to the device for remote update (not efficient as it involves many manual works).
uyeop
  • 21
  • 3
  • It's theoretically possible but I doubt there are any tools for it. Usually this sort of thing is done at the assembly code level. Or you have two entirely separate programs (a bootloader, and your main program) and make it so the bootloader updates the main program. – user253751 Mar 20 '18 at 04:57
  • All global variables you use in B will have to be in a static library and statically linked. Partial upgrade as you suggest is possible but you have to design a very clean architecture and usually, only some specific parts are designed to be updatable (for example only B that relies on static A, C and D) and not "any parts" (understand A or B or C or D). For ease reasons,in microcontrolers, most of the time you just do a standalone bootloader part that updates the whole standalone applicative part (whole A,B,C,D) – Julien Mar 20 '18 at 07:58
  • A very similar question was asked in respect to FreeRTOS at https://stackoverflow.com/questions/21919888/running-applications-from-freertos – Clifford Mar 20 '18 at 11:05
  • An alternative approach is to embed an interpreter and load a script rather than compiled C code. Not very efficient, but simpler and easier to protect and secure perhaps. You could implement your own language or use something like Lua or Forth. – Clifford Mar 20 '18 at 11:10
  • 1
    To me this sounds like a XY problem. Correct way to do this depends on what you actually want to achieve, and your question is very vague about that. – user694733 Mar 20 '18 at 11:12
  • Since it is no longer possible to post an answer, I only suggest an existing project which does something similar to what you need. The new Uzebox bootloader ( https://github.com/Uzebox/uzebox/tree/master/demos/Bootloader5 ) has an exposed API ( http://uzebox.org/wiki/API_Functions#Bootloader_API_Functions ), so essentially you can replace the bootloader, and applications using it's API keep working. This is realized using a call table at a fixed address ( https://github.com/Uzebox/uzebox/blob/master/demos/Bootloader5/kernel/uzeboxCore.s#L164 ) in the bootloader... – Jubatian Mar 22 '18 at 13:48
  • ... doing this in normal C should also be possible, you can create a call table at a fixed address using sections, then you can replace the contents of this table and the functions the table points to later without affecting the code calling them. – Jubatian Mar 22 '18 at 13:51
  • Thanks all, I have added more details to my question and listed some solutions in my initial post. Feel free to add more. @Jubatian Yes I'm aware of the function pointer but my issue is with the compilation and linking process of the updated function. – uyeop Mar 23 '18 at 02:13
  • @uyeop I see, and I think this is an interesting problem. Shouldn't have been closed in my opinion, you even took care to pinpoint that you seek for a solution on bare metal with only the C compiler in your toolset. – Jubatian Mar 26 '18 at 11:36

3 Answers3

1

Dynamic loading and linking requires run-time support - normally provided by an OS. VxWorks for example includes support for that (although the code is normally loaded into RAM over a network or mass-storage file-system rather then Flash or other re-writable ROM).

You could in theory write your own run-time linker/loader. However for it to work, the embedded firmware must contain a symbol table in order to complete the link. The way it works in VxWorks, is the object code to be loaded is partially linked and contains unresolved symbols that are completed by the run-time linker/loader by reference to the embedded symbol table.

Other embedded operating systems that support dynamic loading are:

Another approach that does not require a symbol table is to provide services via a software interrupt API (as used in PC-BIOS and MS-DOS). The loaded module will necessarily have a restricted access to services provided by the API, but because they are interrupts, the actual location of such services does not need to be known to the loadable module, not explicitly linked at run-time.

There is an article on dynamically loading modules in small RTOS systems on Embedded.com:

The author John Carbone works for Express Logic who produce ThreadX RTOS, which gives you an idea of the kind of system it is expected to work on, although the article and method described is not specific to ThreadX.

Clifford
  • 88,407
  • 13
  • 85
  • 165
0

Some approach like this requires that the programmer manually manages all code allocation with their own custom segments. You'd have to know the fixed address of the function and it can't be allowed to grow beyond a certain size.

The flash memory used will dictate the restrictions, namely how large an area do you need to erase before programming. If you can execute code from eeprom/data flash then that's the obvious choice.

Library calls etc are irrelevant as the library functions are most likely stored elsewhere. Or in the rare case where they are inlined, they'll be small. But you might have to write the function in assembler, since C compiler-generated machine code may screw up the calling convention or unexpectedly overwrite registers if taken out of the expected context.

Because all of the above is fairly complex, the normal approach is to only modify const variables, rather than code, and keep those in eeprom/data flash, then have your program act based on those values.

Lundin
  • 195,001
  • 40
  • 254
  • 396
0

I'm assuming you're talking about bare metal with my answer.

First off, linking a new function B() with the original program is relatively simple, particularly with GCC. LD can take a 'symbol file' as input using the --just-symbols option. So, scrape your map file, create the symbol file and use it as an input to your new link. Your resultant elf will contain just your code that assumes all these other symbols are there.

At that point, compile your new function B(), which should be a different name than B() (so we'll choose B_()). It should have the exact same signature as B() or things won't work right. You have to compile with the same headers, etc. that your original code was compiled with or it likely won't work.

Now, depending on how you've architected your original program, life can be easy or a real mess.

If you make your original program with the idea of patching in mind, then the prep is relatively trivial. Identify which functions you might want to patch and then call them through function pointers, e.g.:

void OriginalB(void)
{
    //Original implementation of B goes here
}

void (B*)(void) = OriginalB;

void main(void)
{
    B();  //this calls OriginalB() through the function pointer B.  Once you
          //patch the global function pointer B to point to B_(), then this 
          //code will call your new function.
}

Now your patch program is the original program linked with your B_(), but you somehow have to update the global function pointer B to point to B_() (rather than OriginalB())

Assuming you can use your new elf (or hex file) to update your device, it's pretty easy to just go modify those to change the value of B or assign the new function pointer directly in your code.

If not, then whatever method of injection you need to do also needs to inject a change to the global pointer.

If you didn't prep your original program, then it can be a real bear (but doable) to go modify references to B() to instead jump to your new B_(). It might get super tricky if your new function is too far away for a relative jump, but still doable in theory. I've never actually done it. ;)

If you're trying to patch a ROM, you almost have to have prepped the original ROMmed program to use function points for potential patch points. Or have some support in the ROM hardware to allow limited patching (usually it's just a few locations it will let you patch).

Some of the details may be incorrect for GCC (I use the Keil tools in my professional flow), but the concept is the same. It's doable. It's fragile. There's no standard way of doing this and it's highly tool and application dependent.

Russ Schultz
  • 2,545
  • 20
  • 22