Motivation: Binary size is an important metric; most(embedded) IDEs show this information after you hit the build button
Add checksum to binary
Phase: after linking
What: Modify the output binary(ELF) in place, but this shouldn’t require an external tool; it should be possible to write the thing that modifies the ELF in Rust(build script like)
Motivation: Some microcontrollers won’t boot a binary if it doesn’t have a checksum in a certain place in memory. This checksum can only be computed after linking because some addresses(inputs) are not known until then
Prepare application as bootloader payload
Phase: after linking
What: Modify the output binary(ELF) in place
Motivation: For IoT use cases a device should be upgradeable on the fly. This requires an intermediate control instance which is capable of booting into different application versions depending on a number of factors. To allow applications to be used with a bootloader they need to conform to certain conventions and be relocatable which is usually achieved by a postprocessing step
Zero cost stack overflow protection
Phase: Linking
What: Run linking twice to change the memory layout of a program. The second time with extra linker arguments derived from the output binary from the first linking process
Motivation: The standard memory layout(that you can get using linker scripts) places the stack and static variables in such a way that the stack can grow and overwrite the static variables. Reversing the location of the stack and static variables avoid this problem(see figure in https://blog.japaric.io/stack-overflow-protection/#fixing-it) but changing the layout requires knowing the total size of static variables, which is only known after linking.
Displaying binary size
Add checksum to binary
Prepare application as bootloader payload
Zero cost stack overflow protection