diff options
author | 2022-01-03 11:43:50 +0100 | |
---|---|---|
committer | 2022-01-04 17:40:04 +0100 | |
commit | 68d7f83096379b18bc7610cd064eaf7b8e03608a (patch) | |
tree | bee4c38b6e11a88a5daef84908677a21108ef260 /src | |
parent | 19125ac052fcba1d67de39be3292e34bd6c6d0f4 (diff) | |
download | cortex-m-68d7f83096379b18bc7610cd064eaf7b8e03608a.tar.gz cortex-m-68d7f83096379b18bc7610cd064eaf7b8e03608a.tar.zst cortex-m-68d7f83096379b18bc7610cd064eaf7b8e03608a.zip |
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`...
Diffstat (limited to 'src')
-rw-r--r-- | src/macros.rs | 17 |
1 files changed, 9 insertions, 8 deletions
diff --git a/src/macros.rs b/src/macros.rs index a1ce322..512c932 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()) } } }) |