Linker scripts, addr_of and undefined behaviour
⚓ Rust 📅 2026-01-16 👤 surdeus 👁️ 1A common pattern used in the embedded world works as follows:
First you define an area in the linker script, and expose its boundaries through symbols (keep in mind that in this specific example the area has a fixed size, but this is not always the case, and more often then note the actual size depends on the compilation artifact itself)
/* ... */
.heap (NOLOAD)
{
__heap_start = .;
. += 4M;
__heap_end = .;
} > SRAM
/* ... */
Then in the application code you access that area in this way:
unsafe extern "C" {
unsafe static mut __heap_start: u8;
unsafe static mut __heap_end: u8;
}
unsafe {
allocator::init(addr_of_mut!(__heap_start), addr_of_mut!(__heap_end));
}
My question is, aren't all accesses through addr_of_mut!(__heap_start) and addr_of_mut!(__heap_end) UB?
The main reason for that any access outside that u8 is technically outside its allocation because Rust doesn't now about our linker script shenanigans.
For example, the cortex-m crate does exactly this.
If this is UB, what would be the correct way of doing this? Is casting the pointer to usize and then back to pointer through with_exposed_provenance a better approach? Since it deletes provenance and then gives the compiler a chance to assign a better one? Or is this something we just have to deal with and the compiler is somehow guaranteed to always behave in these scenarios?
1 post - 1 participant
🏷️ Rust_feed