What’s the correct way to ensure cortex-m-rt (or RTIC) uses my custom memory.x so the ELF is linked to 0x08000000 instead of the default 0x00010000?
I’m writing embedded Rust firmware for an STM32H753 using the RTIC framework and stm32h7xx-hal crate. The project compiles successfully, but the generated ELF is only ~150 bytes and contains no .text or vector table.
The ELF should have .text, .vector, etc., starting at 0x08000000, per my memory.x.
$ arm-none-eabi-readelf -l target/thumbv7em-none-eabihf/release/stm32_firmware | grep LOAD
LOAD 0x000000 0x00010000 0x00010000 0x00096 0x00096 R 0x10000
and
$ arm-none-eabi-objdump -h ... | grep .text
# (no results)
objdump:
$ objdump -s target/thumbv7em-none-eabihf/release/stm32_firmware
target/thumbv7em-none-eabihf/release/stm32_firmware: file format elf32-little
Contents of section .defmt.end:
10094 0000 ..
Contents of section .comment:
0000 004c696e 6b65723a 204c4c44 2032302e .Linker: LLD 20.
0010 312e3720 282f6368 65636b6f 75742f73 1.7 (/checkout/s
0020 72632f6c 6c766d2d 70726f6a 6563742f rc/llvm-project/
0030 6c6c766d 20396231 62663463 66303431 llvm 9b1bf4cf041
0040 63316331 66653632 63663033 38393161 c1c1fe62cf03891a
0050 63393034 33313631 35653738 30290072 c90431615e780).r
0060 75737463 20766572 73696f6e 20312e38 ustc version 1.8
0070 392e3020 28323934 38333838 33652032 9.0 (29483883e 2
0080 3032352d 30382d30 342900 025-08-04).
Contents of section .ARM.attributes:
0000 41370000 00616561 62690001 2d000000 A7...aeabi..-...
0010 43322e30 3900060d 074d0800 09020a06 C2.09....M......
0020 0e001101 14011501 17031801 19011b01 ................
0030 1c012201 24012601 ..".$.&.
firmware/stm32/Cargo.toml
[package]
name = "stm32_firmware"
edition = "2021"
[dependencies]
cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] }
cortex-m-rt = { workspace = true }
rtic = { version = "2.0", features = ["thumbv7-backend"] }
# ...
[package.metadata.cortex-m-rt]
memory-x = true
.cargo/config.toml
[build]
target = "thumbv7em-none-eabihf"
[target.thumbv7em-none-eabihf]
runner = "bash firmware/stm32/flash-stm32-opencd.sh"
rustflags = [
"-C", "link-arg=-Tlink.x",
# tried both with and without -Tmemory.x
]
memory.x
MEMORY {
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K
RAM_D1 (rwx): ORIGIN = 0x24000000, LENGTH = 512K
}
REGION_ALIAS(FLASH, FLASH);
REGION_ALIAS(RAM, RAM_D1);
src/main.rs
#![no_std]
#![no_main]
use rtic::app;
#[app(device = stm32h7xx_hal::pac, dispatchers = [EXTI0, EXTI1])]
mod app {
use defmt_rtt as _;
use panic_probe as _;
#[init]
fn init(_: init::Context) -> ((), ()) { loop {} }
}
Ensured memory.x is in the crate root.
Tried adding/removing -Tmemory.x in .cargo/config.toml.
Verified [package.metadata.cortex-m-rt] memory-x = true.
Cleaned/rebuilt with cargo clean.
Still links to 0x00010000.
commands I'm using for reference:
$ cargo clean
$ cargo build -p stm32_firmware --release --target thumbv7em-none-eabihf
After defining build.rs in our project directory:
use std::{env, path::PathBuf};
fn main() {
// Use cortex-m-rt's linker script
println!("cargo:rustc-link-arg=-Tlink.x");
// Make the *containing directory* of memory.x visible to the linker
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
println!("cargo:rustc-link-search={}", manifest_dir.display());
// Rebuild if memory.x changes
println!(
"cargo:rerun-if-changed={}",
manifest_dir.join("memory.x").display()
);
}
We got this error showing the root of problem once the memory. Script was finally being used:
memory.x:5: redefinition of memory region 'FLASH'
\>\>\> REGION_ALIAS(FLASH, FLASH); \>\>\>
^ error: could not compile stm32_firmware (bin "stm32_firmware") due to 1 previous error
So quite literally just needed to remove the REGION_ALIAS(FLASH, FLASH); line and the binary is looking scrumptious now
@thebusybee thanks to him for letting me know verbose still exists lol. Using the verbose appendage I confirmed the linker flags are being appended to the build commands defined in the .config file ruling that out, revealing the memory. Wasn't being used in the first place.