Skip to content

Commit

Permalink
rust: add offset_of macro
Browse files Browse the repository at this point in the history
This macro is used to compute the offset of a field in a struct.

This commit enables two unstable features that are necessary for using
the macro in a constant. However, this is not a problem as the macro
will become available from the Rust standard library soon [1]. The
unstable features can be disabled again once that happens.

The macro in this patch does not support sub-fields. That is, you cannot
write `offset_of!(MyStruct, field.sub_field)` to get the offset of
`sub_field` with `field`'s type being a struct with a field called
`sub_field`. This is because `field` might be a `Box<SubStruct>`, which
means that you would be trying to compute the offset to something in an
entirely different allocation. There's no easy way to fix the current
macro to support subfields, but the version being added to the standard
library should support it, so the limitation is temporary and not a big
deal.

Link: rust-lang/rust#106655 [1]
Signed-off-by: Alice Ryhl <[email protected]>
Co-Developed-by: Wedson Almeida Filho <[email protected]>
Signed-off-by: Wedson Almeida Filho <[email protected]>
  • Loading branch information
Darksonn authored and nbdd0121 committed May 10, 2023
1 parent eb5e46f commit 56fab21
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 1 deletion.
35 changes: 35 additions & 0 deletions rust/kernel/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#![no_std]
#![feature(allocator_api)]
#![feature(coerce_unsized)]
#![feature(const_ptr_offset_from)]
#![feature(const_refs_to_cell)]
#![feature(dispatch_from_dyn)]
#![feature(new_uninit)]
#![feature(receiver_trait)]
Expand Down Expand Up @@ -100,3 +102,36 @@ fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
// instead of `!`. See <https://github.com/rust-lang/rust-bindgen/issues/2094>.
loop {}
}

/// Calculates the offset of a field from the beginning of the struct it belongs to.
///
/// # Examples
///
/// ```
/// #[repr(C)]
/// struct Test {
/// a: u64,
/// b: u32,
/// }
///
/// assert_eq!(kernel::offset_of!(Test, b), 8);
/// ```
#[macro_export]
macro_rules! offset_of {
($type:ty, $field:ident) => {{
let tmp = ::core::mem::MaybeUninit::<$type>::uninit();
let outer = tmp.as_ptr();
// To avoid warnings when nesting `unsafe` blocks.
#[allow(unused_unsafe)]
// SAFETY: The pointer is valid and aligned, just not initialised; `addr_of` ensures that
// we don't actually read from `outer` (which would be UB) nor create an intermediate
// reference.
let inner = unsafe { ::core::ptr::addr_of!((*outer).$field) } as *const u8;
// To avoid warnings when nesting `unsafe` blocks.
#[allow(unused_unsafe)]
// SAFETY: The two pointers are within the same allocation block.
unsafe {
inner.offset_from(outer as *const u8) as usize
}
}};
}
2 changes: 1 addition & 1 deletion scripts/Makefile.build
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ $(obj)/%.lst: $(src)/%.c FORCE
# Compile Rust sources (.rs)
# ---------------------------------------------------------------------------

rust_allowed_features := new_uninit
rust_allowed_features := new_uninit,const_ptr_offset_from_const_refs_to_cell

rust_common_cmd = \
RUST_MODFILE=$(modfile) $(RUSTC_OR_CLIPPY) $(rust_flags) \
Expand Down

0 comments on commit 56fab21

Please sign in to comment.