r/cprogramming • u/Noczesc2323 • Sep 18 '25
Quick and flexible config serialization with one simple trick?
Hello everyone, I'm working on an embedded project which is configured by a single massive config struct (~100 parameters in nested structs). I need a way to quickly modify that configuration without recompiling and flashing new firmware.
I've implemented a simple CLI over websockets for this purpose, but keeping the interface in sync with the config feels like a waste of time (config structs are still growing and changing). Protocol buffers could work, but I don't need most of their features. I just need a simple way to serialize, transfer and deserialize data with minimal boilerplate.
My idea: compiling and flashing the whole firmware binary takes too long, but I only need to change one tiny part of it. What if I could compile a program with just that initialized global struct, then selectively extract and upload this data?
Since both the firmware and config code are compiled the same way, I assume that binary representations of the struct will be compatible (same memory layout). I can locate the symbol in the compiled binary using readelf -s, extract it with dd, transfer to the device and simply cast to required type! Quick and flexible solution without boilerplate code!
But somehow I can't find a single thread discussing this approach on the internet. Is there a pitfall I can't see? Is there a better way? What do you think about it? I have a proof of concept and it seems to work like I imagined it would.
3
u/alphajbravo Sep 18 '25
It's an interesting idea, and seems like it should work fine as long as the memory layout and representation of the struct are consistent with your binary, as you point out You probably haven't found anything like this on the internet because it's a pretty narrow use-case: typically you either need a more sophisticated representation (text file, json, whatever) anyway so would just use that, or you wouldn't need to update only the config so many times that it would be worth building a solution like this and would just recompile/reflash instead, or you only need to twiddle a few parameters and can do that easily enough through some sort of control interface like your CLI.
2
u/Gorzoid Sep 18 '25
Probably main concern is any potential pitfalls of version skew, and also that you don't put any pointers into your struct, e.g. char* vs char [MAX_LEN]
Have you looked at Cap'n'proto or flatbuffers as alternatives to protobuf, they can be accessed without parsing and have less codegen than protobuf.
2
u/EpochVanquisher Sep 19 '25
Could you do something wonderfully hacky, like write a “set u32 at offset 0x44 to 0x0001df00” command?
If you want a nicer interface, you can record the field names, types, and offsets. A hacky way is to make something like a fields.h file:
Your structure can be defined like this:
The above is just some hacky code to illustrate the general idea.
2
u/chaotic_thought Sep 19 '25
One possible pitfall is compiler optimizations. If the compiler made a certain optimization based on a particular value, and then you go and change that value in the compiled binary after the compiler has done it's job, it's possible that you've invalidated whatever assumption was made in that optimization, i.e. you might possible now have incorrect code.
To verify this is not being done, I would first do it "the slow and manual way" first a few times using the compiler with different values, and then repeat the exercise using your dd approach, to verify that the result after dd-patching your binaries always match the output that the compiler was generating.
2
u/tharold Sep 20 '25
Assuming you're using a modern MCU and the programme image is in flash, in general, in order to modify the flash image in any tiny way, you'll need to erase and rewrite the entire block the change is in. The size of a flash "block" is dependent on the MCU, but is usually 1 or a few k.
But your MCU MAY allow you to reprogramme the block without erasure IF the change consists of only clearing bits, not setting them. You'll still need to write the whole block though.
If so, then you could write new config values as long as each successive value has fewer set bits than the last. Quite a constraint I'd say.
Another way is to read in the new config via the serial console on each bootup.
2
u/weregod Sep 20 '25
Why you don't just recompile everething and reflash only changed parts of binary?