This repo demonstrates how to control the placement of symbols or crates in specific offsets in flash for embedded Rust crates using the memory.x file for embedded projects using cortex-m mcus.
The crate-placement-test crate is the root crate that will be flashed to the device, the amazing-crate-placement-crate is the crate that will receive a custom location in flash.
For this demo the placements are stored in the sections.x file:
SECTIONS {
.second_flash :
{
*(.text.*amazing_crate_placement_crate*)
*(.rodata.*amazing_crate_placement_crate*)
*(.data.rel.ro.*amazing_crate_placement_crate*)
*(.text.*embassy_time*);
*(.rodata.*embassy_time*);
*(.data.rel.ro.*embassy_time*);
. = ALIGN(4); /* Pad .text to the alignment to workaround overlapping load section bug in old lld (taken from cortex-m-rt link.x.in) */
} > SECONDFLASH
}
Here the amazing_crate_placement_crate and the embassy_time crates are placed in the secondflash section.
The crates are surrounded by * wildcards and prepended with the different sections we want to include in the custom section.
It is important to match only the specified sections as matching more might break things.
Moving defmt sections will break defmt printing for instance.
Additionally the .bss and the .data sections are not included as they are initialized to memory on startup.
They cannot be modified by simply writing if they are on flash so they should not be moved.
The .bss sections are zero initialized meaning moving them to flash would not actually free up storage.
The mechanism in cortex-m-rt that is normally responsible for copying the .data section doesn't support multiple .data sections.
This means if you want to move the .data section an additional runtime copying mechanism needs to be provided to replace the normal mechanism.
Rust adds the crate name to symbols meaning the crate name can be used here but more specific naming (like function names) could be used here as well (note that functions would be in .text. sections).
The sections.x file is then included in the memory.x file where the location of the memory section is defined:
INCLUDE sections.x
MEMORY
{
FLASH : ORIGIN = 0x00000000, LENGTH = 512K
SECONDFLASH : ORIGIN = 512K, LENGTH = 512K
RAM : ORIGIN = 0x20000000, LENGTH = 128K
}
The output can be verified using objdump on the resulting elf file:
objdump -t ./target/thumbv8m.main-none-eabihf/debug/crate-placement-test | grep amazing_crate_placement_crate
Result:
0008006c l O .second_flash 00000008 _ZN29amazing_crate_placement_crate6STRING17h818aaefa4ddecde2E
00080062 l O .second_flash 0000000a _ZN29amazing_crate_placement_crate4DATA17h9f60ba7e9a7f5c6eE
00000015 g O .defmt 00000001 {"package":"amazing-crate-placement-crate","tag":"defmt_info","data":"Hello from test! {}, {}","disambiguator":"4230908633098738326","crate_name":"amazing_crate_placement_crate"}
00000021 g O .defmt 00000001 {"package":"amazing-crate-placement-crate","tag":"defmt_println","data":"Just a normal print test","disambiguator":"12335086240275054136","crate_name":"amazing_crate_placement_crate"}
00080001 g F .second_flash 00000062 _ZN29amazing_crate_placement_crate13test_function17h4689e49d00af5f4dE
The output shows mangled symbol names. The -C can be used to demangle the symbols.
Note that defmt is not moved and it shouldn't be.
Rust allows linking different versions of the same in a single executable thanks to symbol mangling. Right now this solution will place both versions of the crates in the same assigned section. It is technically possible to differentiate between them in the linker script. The linker works with the mangled versions that contain the hash at the end of the symbol identifying the different versions. If you find a way to trace back the original crate you could simply put the whole mangled name in the linker script. I have not found a way to figure out what crate a symbol came from. It seems the hash is made in the final build step. Before the root crate is built and linked the crates will have the same hash but after that the hashes will be different. This means only rustc knows what crate a symbol came from afterwards.