From 19125ac052fcba1d67de39be3292e34bd6c6d0f4 Mon Sep 17 00:00:00 2001 From: Rahix Date: Mon, 3 Jan 2022 11:32:26 +0100 Subject: [PATCH 1/3] macros: Allow setting a name for singleton!() statics Right now, the `singleton!()` macro always creates a static named `VAR`. This is annoying when digging through objdump output or digging into memory with a debugger because it is hard to see what singleton you're looking at when they are all called `<...>::{{closure}}::VAR`. To make it a bit nicer, allow setting the name of the generated static to some meaningful identifier which can then be cross-referenced in debugger output, for example with singleton!(FOO_BUFFER: [u8; 1024] = [0u8; 1024]); There is no other side-effects to this change - the identifier is never visible to other code because it is still contained in the closure of the macro. --- src/macros.rs | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index 66b75b17..a1ce3227 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -30,9 +30,12 @@ macro_rules! iprintln { /// `None` variant the caller must ensure that the macro is called from a function that's executed /// at most once in the whole lifetime of the program. /// -/// # Note +/// # Notes /// This macro is unsound on multi core systems. /// +/// For debuggability, you can set an explicit name for a singleton. This name only shows up the +/// the debugger and is not referencable from other code. See example below. +/// /// # Example /// /// ``` no_run @@ -50,15 +53,20 @@ macro_rules! iprintln { /// fn alias() -> &'static mut bool { /// singleton!(: bool = false).unwrap() /// } +/// +/// fn singleton_with_name() { +/// // A name only for debugging purposes +/// singleton!(FOO_BUFFER: [u8; 1024] = [0u8; 1024]); +/// } /// ``` #[macro_export] macro_rules! singleton { - (: $ty:ty = $expr:expr) => { + ($name:ident: $ty:ty = $expr:expr) => { $crate::interrupt::free(|_| { - static mut VAR: Option<$ty> = None; + static mut $name: Option<$ty> = None; #[allow(unsafe_code)] - let used = unsafe { VAR.is_some() }; + let used = unsafe { $name.is_some() }; if used { None } else { @@ -66,16 +74,19 @@ macro_rules! singleton { #[allow(unsafe_code)] unsafe { - VAR = Some(expr) + $name = Some(expr) } #[allow(unsafe_code)] unsafe { - VAR.as_mut() + $name.as_mut() } } }) }; + (: $ty:ty = $expr:expr) => { + $crate::singleton!(VAR: $ty = $expr) + }; } /// ``` compile_fail From 68d7f83096379b18bc7610cd064eaf7b8e03608a Mon Sep 17 00:00:00 2001 From: Rahix Date: Mon, 3 Jan 2022 11:43:50 +0100 Subject: [PATCH 2/3] macros: Don't use Option in singleton!() As detailed in rust-embedded/cortex-m#364, niche optimization of the `Option` used in the `singleton!()` macro can lead to the initial value of the static to contain non-zero bits. This in turn leads to the whole static being moved from `.bss` to `.data` which means it eats up flash space for no reason. Especially if the singleton stores a particularly large type, this can be quite problematic. Prevent this by using an explicit boolean flag instead of the `Option` type. This is not quite as nice but at least there is no chance for the `singleton!()` to end up in `.data`... --- src/macros.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index a1ce3227..512c9323 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -63,10 +63,14 @@ macro_rules! iprintln { macro_rules! singleton { ($name:ident: $ty:ty = $expr:expr) => { $crate::interrupt::free(|_| { - static mut $name: Option<$ty> = None; + // this is a tuple of a MaybeUninit and a bool because using an Option here is + // problematic: Due to niche-optimization, an Option could end up producing a non-zero + // initializer value which would move the entire static from `.bss` into `.data`... + static mut $name: (::core::mem::MaybeUninit<$ty>, bool) = + (::core::mem::MaybeUninit::uninit(), false); #[allow(unsafe_code)] - let used = unsafe { $name.is_some() }; + let used = unsafe { $name.1 }; if used { None } else { @@ -74,12 +78,9 @@ macro_rules! singleton { #[allow(unsafe_code)] unsafe { - $name = Some(expr) - } - - #[allow(unsafe_code)] - unsafe { - $name.as_mut() + $name.1 = true; + $name.0 = ::core::mem::MaybeUninit::new(expr); + Some(&mut *$name.0.as_mut_ptr()) } } }) From 632af2e78241416420b8004820d6f386cfabeae8 Mon Sep 17 00:00:00 2001 From: Rahix Date: Tue, 4 Jan 2022 10:29:16 +0100 Subject: [PATCH 3/3] Update CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1e61b6b..04bf9d94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - ITM: add `configure` API (#342). - TPIU: add API for *Formatter and Flush Control* (FFCR) and *Selected Pin Control* (SPPR) registers (#342). - Add `std` and `serde` crate features for improved host-side ITM decode functionality when working with the downstream `itm`, `cargo-rtic-scope` crates (#363, #366). +- Added the ability to name the statics generated by `singleton!()` for better debuggability (#364, #380). + +### Fixed +- Fixed `singleton!()` statics sometimes ending up in `.data` instead of `.bss` (#364, #380). ## [v0.7.4] - 2021-12-31