From ccfb0f8b5098fe6bb161a8fef34a5495cd79fd02 Mon Sep 17 00:00:00 2001 From: David Rheinsberg Date: Mon, 27 Apr 2026 13:09:13 +0200 Subject: [PATCH 01/10] osi/ffi/abi: expose `abi::shared` Allow external access to `abi::shared`, but mark it as hidden. This allows `sys` to meddle with the native abi but re-use `abi::shared`. Signed-off-by: David Rheinsberg --- lib/osi/src/ffi/abi.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/osi/src/ffi/abi.rs b/lib/osi/src/ffi/abi.rs index 829c902..d9d6006 100644 --- a/lib/osi/src/ffi/abi.rs +++ b/lib/osi/src/ffi/abi.rs @@ -44,7 +44,8 @@ type Le = crate::ffi::Integer< // This module is imported by all ABIs and provides default symbols valid on // all targets. -mod shared { +#[doc(hidden)] +pub mod shared { /// Creates a number by converting the input value from native /// representation into the representation of the target type. /// From e9ad57f34f106b1cf92b8185b003417dba11901b Mon Sep 17 00:00:00 2001 From: David Rheinsberg Date: Mon, 27 Apr 2026 13:10:13 +0200 Subject: [PATCH 02/10] osi/ffi/abi: add aarch64_sysv Add the Sys-V ABI of Aarch64. Signed-off-by: David Rheinsberg --- lib/osi/src/ffi/abi.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/lib/osi/src/ffi/abi.rs b/lib/osi/src/ffi/abi.rs index d9d6006..7f53acb 100644 --- a/lib/osi/src/ffi/abi.rs +++ b/lib/osi/src/ffi/abi.rs @@ -97,6 +97,36 @@ pub mod native { pub use super::shared::*; } +/// # System-V aarch64 ABI +/// +/// This ABI represents the 64-bit ABI of System-V for aarch64 systems. It is +/// used by most UNIX compatible systems, including Linux. +pub mod aarch64_sysv { + use crate::align; + + pub type I8 = super::Le>; + pub type I16 = super::Le>; + pub type I32 = super::Le>; + pub type I64 = super::Le>; + pub type I128 = super::Le>; + pub type Isize = super::Le>; + + pub type U8 = super::Le>; + pub type U16 = super::Le>; + pub type U32 = super::Le>; + pub type U64 = super::Le>; + pub type U128 = super::Le>; + pub type Usize = super::Le>; + + pub type F32 = super::Le>; + pub type F64 = super::Le>; + + pub type Addr = super::Le>; + pub type Ptr = crate::ffi::Pointer; + + pub use super::shared::*; +} + /// # System-V x86 ABI /// /// This ABI represents the 32-bit ABI of System-V for x86 systems. It is used From 7afc310e86dbed6e0d63a31a27b2599cd269f0ef Mon Sep 17 00:00:00 2001 From: David Rheinsberg Date: Mon, 27 Apr 2026 13:10:34 +0200 Subject: [PATCH 03/10] osi/ffi/abi: auto -> target Use the canonical name `target` rather than the otherwise unused term `auto` to refer to the compilation target platform. Signed-off-by: David Rheinsberg --- lib/osi/src/ffi/abi.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/osi/src/ffi/abi.rs b/lib/osi/src/ffi/abi.rs index 7f53acb..302508e 100644 --- a/lib/osi/src/ffi/abi.rs +++ b/lib/osi/src/ffi/abi.rs @@ -16,7 +16,7 @@ //! to get a native Rust experience. This is suitable if foreign data access //! is not needed. //! -//! [`auto`] is an alias of one of the other ABIs and represents the target +//! [`target`] is an alias of one of the other ABIs and represents the target //! platform. Unlike [`native`], this does not necessarily use native Rust //! data-types, but is a real alias to one of the other fixed definitions of //! platform ABIs. @@ -187,28 +187,34 @@ pub mod x86_64_sysv { pub use super::shared::*; } +#[cfg(all( + target_arch = "aarch64", + target_family = "unix", +))] +pub use aarch64_sysv as target; + #[cfg(all( target_arch = "x86", target_family = "unix", ))] -pub use x86_sysv as auto; +pub use x86_sysv as target; #[cfg(all( target_arch = "x86_64", target_family = "unix", ))] -pub use x86_64_sysv as auto; +pub use x86_64_sysv as target; #[cfg(all( target_arch = "x86", target_env = "msvc", target_family = "windows", ))] -pub use x86_win as auto; +pub use x86_win as target; #[cfg(all( target_arch = "x86_64", target_env = "msvc", target_family = "windows", ))] -pub use x86_64_win as auto; +pub use x86_64_win as target; From 0c0c2141a6be7dc3dc6aeac9bfb5e8d658d5015b Mon Sep 17 00:00:00 2001 From: David Rheinsberg Date: Mon, 27 Apr 2026 13:11:00 +0200 Subject: [PATCH 04/10] osi/wishlist: rustdoc comments for re-exports Extend the wishlist with a new item for documentation of re-exports of other modules. So far, rustdoc does not allow documenting them, yet the way our platform aliases work would really benefit from documentation on re-exports. Signed-off-by: David Rheinsberg --- lib/osi/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/osi/src/lib.rs b/lib/osi/src/lib.rs index 4a32003..5ddeac3 100644 --- a/lib/osi/src/lib.rs +++ b/lib/osi/src/lib.rs @@ -15,6 +15,10 @@ // if the self-type was shown, or there was another way to quickly jump to // it via an anchor. // +// - rustdoc pub-use: There is currently no way to document `pub use` +// statements. Given how FFI modules in `sys` export aliases, documenting +// those would be great. +// // - rustfmt optout: There is no global opt-out for rustfmt. While individual // items can be annotated with `#[rustfmt::skip]`, the root module of a // crate cannot be annotated like this (NB: inner attributes like From ea55dff1879096d39f2b9f4d40e1eebefc4200f0 Mon Sep 17 00:00:00 2001 From: David Rheinsberg Date: Mon, 27 Apr 2026 13:06:46 +0200 Subject: [PATCH 05/10] sys: rework ffi layout Rework the sys::ffi file-system layout and platform generation. This makes it a lot easier to add new platforms, and no longer requires patching multiple places. This also adds aarch64 support, showing how new platforms can be easily added. Signed-off-by: David Rheinsberg --- lib/sys/src/ffi.rs | 49 ------ lib/sys/src/ffi/linux.rs | 116 --------------- lib/sys/src/ffi/linux/aarch64/mod.rs | 13 ++ lib/sys/src/ffi/linux/libc/mod.rs | 26 +++- lib/sys/src/ffi/linux/mod.rs | 147 ++++++++++++++++++ lib/sys/src/ffi/linux/native/.gitignore | 1 + lib/sys/src/ffi/linux/native/mod.rs | 35 ----- lib/sys/src/ffi/linux/test.rs | 188 +++++++++++++++++++++++- lib/sys/src/ffi/linux/x86/mod.rs | 2 +- lib/sys/src/ffi/linux/x86_64/mod.rs | 2 +- lib/sys/src/ffi/mod.rs | 73 +++++++++ lib/sys/src/{linux.rs => linux/mod.rs} | 2 +- 12 files changed, 443 insertions(+), 211 deletions(-) delete mode 100644 lib/sys/src/ffi.rs delete mode 100644 lib/sys/src/ffi/linux.rs create mode 100644 lib/sys/src/ffi/linux/aarch64/mod.rs create mode 100644 lib/sys/src/ffi/linux/mod.rs create mode 100644 lib/sys/src/ffi/linux/native/.gitignore delete mode 100644 lib/sys/src/ffi/linux/native/mod.rs create mode 100644 lib/sys/src/ffi/mod.rs rename lib/sys/src/{linux.rs => linux/mod.rs} (84%) diff --git a/lib/sys/src/ffi.rs b/lib/sys/src/ffi.rs deleted file mode 100644 index 66bb606..0000000 --- a/lib/sys/src/ffi.rs +++ /dev/null @@ -1,49 +0,0 @@ -//! # Definitions of System Interfaces -//! -//! For all system interfaces the respective raw definitions of constants, -//! structures, types, and more are provided in this module. This allows use of -//! these definitions outside of possible higher abstractions. -//! -//! The definitions are transposed into Rust following a set of rules and -//! guidelines, thus yielding predictable type names and definitions. The idea -//! is to produce the same predictable as result, as if a tool like `bindgen` -//! was used. -//! -//! This module only provides the definitions of the system interfaces, but no -//! implementation. This is left to other modules (or the user). -//! -//! Unless explicitly specified, the definitions are provided in an -//! architecture independent format. They are suitable for access of foreign -//! system architectures, as is common for introspection or debugging. -//! -//! ## Transpose Rules -//! -//! While this module attempts to be a direct mapping to the respective -//! protocols and specifications, slight adjustments are usually necessary to -//! account for the peculiarities of Rust: -//! -//! * All names follow the standard Rust naming scheme, using `CamelCase` for -//! types, `UPPER_CASE` for constants, and `snake_case` for everything else. -//! -//! * Prefixes are stripped if the Rust module or type-system provides a -//! suitable prefix. -//! -//! * C-enums are always provided as raw integer type, rather than Rust enum -//! to allow arbitrary discriminants to be used. This is particularly -//! important when the interface allows for custom/vendor extensions, since -//! then Rust enums would be unable to represent the unused ranges. -//! -//! * Pointers are always represented as `NonNull` or `Option` and -//! thus strip any `const` annotations. This is on purpose, since the -//! classic C-const annotations cannot be transposed to Rust in a sensible -//! way. For architecture-independent representations, see `osi::ffi`. -//! -//! ## Native Alias -//! -//! If suitable, a module will expose the types native to the compilation -//! target under a `native` alias (or with `*n` suffix). This allows easy -//! interaction with each module on the running system. However, it will -//! prevent any cross-architecture interaction, or interaction with non-native -//! actors. - -pub mod linux; diff --git a/lib/sys/src/ffi/linux.rs b/lib/sys/src/ffi/linux.rs deleted file mode 100644 index 6e333a0..0000000 --- a/lib/sys/src/ffi/linux.rs +++ /dev/null @@ -1,116 +0,0 @@ -//! # Definitions of Linux System Interfaces -//! -//! For all high-level abstractions of Linux system interfaces that are -//! provided by this crate, the respective raw definitions of Linux kernel -//! interface constants, structures, types, and more are provided in this -//! module. This allows use of these definitions independent of higher -//! abstractions. -//! -//! This module exposes a set of platform-modules, which are all syntactically -//! equivalent, but define the interfaces for different platforms. Several -//! pseudo-modules are provided, which either alias another platform-module or -//! provide a virtual platform based on another one. In most cases, you want -//! to use the [`native`] platform-module to get access to all the interfaces -//! for the platform of the compilation target. -//! -//! ## Completeness -//! -//! This module does not claim complete coverage of all Linux kernel -//! interfaces. However, all Linux kernel interfaces are in-scope of this -//! module (usually this means the interface is defined in the `uapi` headers -//! of the linux kernel). Feel free to add more interfaces if needed. - -// We provide FFI definitions for all supported platforms simultaneously. This -// is especially useful for debugging utilities which need to access foreign -// platform data, and thus the foreign ABI will be different to the native one. -// This, however, requires manually defining all the interfaces for all -// platforms. To aid in this, we use a few tricks: -// -// - Each platform exposes a sub-module `abi`, which defines the basic -// data-types of the platform. This is taken from [`osi::ffi::abi`] and -// simply re-exported. -// - Common definitions are shared in the [`common`] sub-module. This -// sub-module is not exposed by itself, but has to be included manually by -// each platform. The module makes use of other definitions of the platform -// via `use super::XYZ`. See `common/mod.rs` for details on which -// definitions it requires. This is also the reason why the module is -// recompiled for each platform, since its implementation depends on other -// platform details. -// - The `libc` platform is available if the `libc` feature is selected. It is -// not a real platform, but rather defines the same API as the other -// platforms but via aliases to the types of `libc`. It can be used for -// platforms that are not natively supported by this crate, yet. While the -// FFI definitions do not require the C library to be linked, dependent -// users will likely pull in the C library if the `libc` feature is used. -// - The `native` platform is also not a real platform. Instead it is an -// alias for one of the other platforms but using the native Rust primitives -// via [`osi::ffi::abi::native`]. If a platform is not supported, this will -// even use the `libc` platform. -// - Ideally, we would provide FFI definitions via Rust traits, with the -// platform ABI as type generic. Unfortunately, this would severly limit the -// usability due to rustc restrictions (e.g., no inherently const methods in -// traits, no associated types for inherent impls, ...). Furthermore, since -// there are no module-generics in Rust, we instead recompile the FFI -// definitions for each platform, sharing as much as possible. -// Note that this is why we use `.//mod.rs` rather than -// `./.rs`, to ensure the platform directory exists and our usage -// of `path = "../[...]"` works. - -#![allow(clippy::duplicate_mod)] - -#[cfg(test)] -mod test; - -pub mod libc; -pub mod native; - -/// # Platform Module for x86 -/// -/// This module exposes all supported interfaces of [`crate::ffi::linux`] for -/// the x86 platform. -pub mod x86 { - pub use osi::ffi::abi::x86_sysv as abi; - - #[path = "mod.rs"] - mod inner; - - pub use inner::*; -} - -/// # Platform Module for x86_64 -/// -/// This module exposes all supported interfaces of [`crate::ffi::linux`] for -/// the x86_64 platform. -pub mod x86_64 { - pub use osi::ffi::abi::x86_64_sysv as abi; - - #[path = "mod.rs"] - mod inner; - - pub use inner::*; -} - -osi::cfg::cond! { - (doc) { - /// # Pseudo-Module for the Target Platform - /// - /// This module is a straight alias of the platform-module that matches - /// the compilation target. If no platform-module exists for the - /// compilation target, this will be an alias of `native`. - /// - /// For documentation purposes, this is always an alias of `native`. - pub mod target { - #[doc(inline)] - pub use super::native::*; - } - }, - (target_arch = "x86") { - pub use x86 as target; - }, - (target_arch = "x86_64") { - pub use x86_64 as target; - }, - { - pub use native as target; - }, -} diff --git a/lib/sys/src/ffi/linux/aarch64/mod.rs b/lib/sys/src/ffi/linux/aarch64/mod.rs new file mode 100644 index 0000000..53a660c --- /dev/null +++ b/lib/sys/src/ffi/linux/aarch64/mod.rs @@ -0,0 +1,13 @@ +// Platform Module for aarch64 +// +// This module is included multiple times by `../mod.rs`, using outer +// comments for documentation. It is also the responsibility of the caller +// to define the ABI to use. This module simply re-uses it via +// `use super::abi`. + +use super::abi; + +#[path = "../common/mod.rs"] +mod common; + +pub use common::*; diff --git a/lib/sys/src/ffi/linux/libc/mod.rs b/lib/sys/src/ffi/linux/libc/mod.rs index 2a90d59..a38df4f 100644 --- a/lib/sys/src/ffi/linux/libc/mod.rs +++ b/lib/sys/src/ffi/linux/libc/mod.rs @@ -8,6 +8,8 @@ //! Only a compile-time dependency to the Rust wrappers of the C library //! (i.e., the [`libc`] crate) is needed. //! +//! ## Documentation +//! //! This module does not provide any documentation for its exposed symbols. //! Documentation for all exposed symbols is available in the //! [`native`](crate::ffi::linux::native) module (or any of the platform @@ -15,6 +17,28 @@ #![cfg(feature = "libc")] -pub use osi::ffi::abi::native as abi; +pub mod abi { + pub type I8 = i8; + pub type I16 = libc::__s16; + pub type I32 = libc::__s32; + pub type I64 = libc::__s64; + pub type I128 = i128; + pub type Isize = libc::ssize_t; + + pub type U8 = libc::__u8; + pub type U16 = libc::__u16; + pub type U32 = libc::__u32; + pub type U64 = libc::__u64; + pub type U128 = u128; + pub type Usize = libc::size_t; + + pub type F32 = f32; + pub type F64 = f64; + + pub type Addr = osi::ffi::abi::native::Addr; + pub type Ptr = osi::ffi::abi::native::Ptr; + + pub use osi::ffi::abi::shared::*; +} pub mod errno; diff --git a/lib/sys/src/ffi/linux/mod.rs b/lib/sys/src/ffi/linux/mod.rs new file mode 100644 index 0000000..ab13db2 --- /dev/null +++ b/lib/sys/src/ffi/linux/mod.rs @@ -0,0 +1,147 @@ +//! # Definitions of Linux System Interfaces +//! +//! This module exposes the raw definitions of the Linux kernel system +//! interfaces, including interface constants, structures, types, and more. +//! It allows direct access to Linux system interfaces bypassing any high-level +//! abstraction. The module does not strive for completeness, but any +//! interfaces that are part of the Linux kernel `uapi` are in-scope. +//! +//! ## Platforms +//! +//! Since Linux system interfaces differ depending on the target platform, the +//! interfaces are provided once for each supported platform. A separate +//! sub-module exists for each platform, but they all expose the same APIs (but +//! with differences specific to the architecture). +//! +//! When fixed access to a specific platform is required, the modules can be +//! used directly (e.g., reading core-dumps of a specific platform, independent +//! of the host platform). But if access to the target platform of the +//! compilation is needed, then one of the following aliases is recommended: +//! +//! - `native`: Exposes the system interfaces using the native +//! compiler primitives for the target platform. That is, integers are +//! represented with the builtin types `u32`, `i64`, ... They use the +//! native endianness and alignment. This module is **not** an alias, but +//! compiled as a unique, separate platform. +//! - `libc`: Exposes the system interfaces using the types of the `libc` +//! crate. Only available under the `libc` feature. Like `native`, this is +//! compiled as a unique, separate platform. +//! - `target`: Alias for the platform module matching the target platform. If +//! no such platform module exists, the alias is not available. + +// We provide FFI definitions for all supported platforms simultaneously. This +// is especially useful for debugging utilities which need to access foreign +// platform data, and thus the foreign ABI will be different to the native one. +// This, however, requires manually defining all the interfaces for all +// platforms. To aid in this, we use a few tricks: +// +// - Each platform exposes a sub-module `abi`, which defines the basic +// data-types of the platform. This is taken from [`osi::ffi::abi`] and +// simply re-exported. +// - Common definitions are shared in the [`common`] sub-module. This +// sub-module is not exposed by itself, but has to be included manually by +// each platform. The module makes use of other definitions of the platform +// via `use super::XYZ`. See `common/mod.rs` for details on which +// definitions it requires. This is also the reason why the module is +// recompiled for each platform, since its implementation depends on other +// platform details. +// - The `libc` platform is available if the `libc` feature is selected. It is +// not a real platform, but rather defines the same API as the other +// platforms but via aliases to the types of `libc`. It can be used for +// platforms that are not natively supported by this crate, yet. While the +// FFI definitions do not require the C library to be linked, dependent +// users will likely pull in the C library if the `libc` feature is used. +// - The `native` platform is also not a real platform. Instead it is an +// alias for one of the other platforms but using the native Rust primitives +// via [`osi::ffi::abi::native`]. If a platform is not supported, this will +// even use the `libc` platform. +// - Ideally, we would provide FFI definitions via Rust traits, with the +// platform ABI as type generic. Unfortunately, this would severly limit the +// usability due to rustc restrictions (e.g., no inherently const methods in +// traits, no associated types for inherent impls, ...). Furthermore, since +// there are no module-generics in Rust, we instead recompile the FFI +// definitions for each platform, sharing as much as possible. +// Note that this mandates `.//mod.rs` rather than +// `./.rs`, to ensure the platform directory exists and our usage +// of `path = "../[...]"` works. + +#![allow(clippy::duplicate_mod)] + +#[cfg(test)] +mod test; + +pub mod libc; + +macro_rules! impl_platform { + ( + $platform:ident, + $cfg:meta, + $path:meta, + $abi:path + $(,)? + ) => { + #[doc = concat!("# Platform Module for ", stringify!($platform))] + /// + /// This module exposes all supported interfaces of + /// [`crate::ffi::linux`] for the + #[doc = concat!(stringify!($platform), " platform.")] + pub mod $platform { + pub use $abi as abi; + + #[$path] + mod inner; + + pub use inner::*; + } + + // # Platform Module for the target platform + // + // This module is a straight alias of the platform module that matches + // the compilation target. If no platform module exists for the + // compilation target, this alias is not provided. + #[$cfg] + pub use $platform as target; + + /// # Pseudo-Module for the Native Platform + /// + /// This module behaves like an alias of the platform module that + /// matches the compilation target. However, it is not a straight alias + /// but a recompilation of the platform module with the Rust primitives + /// as ABI. + /// + /// If no platform module matches the compilation target, this will use + /// the `libc` module (if enabled). If the latter is not enabled, this + /// module will not exist. + #[$cfg] + pub mod native { + pub use osi::ffi::abi::native as abi; + + #[$path] + mod inner; + + #[allow(unused)] + pub use inner::*; + } + }; +} + +impl_platform!( + aarch64, + cfg(target_arch = "aarch64"), + path = "../aarch64/mod.rs", + osi::ffi::abi::aarch64_sysv, +); + +impl_platform!( + x86, + cfg(target_arch = "x86"), + path = "../x86/mod.rs", + osi::ffi::abi::x86_sysv, +); + +impl_platform!( + x86_64, + cfg(target_arch = "x86_64"), + path = "../x86_64/mod.rs", + osi::ffi::abi::x86_64_sysv, +); diff --git a/lib/sys/src/ffi/linux/native/.gitignore b/lib/sys/src/ffi/linux/native/.gitignore new file mode 100644 index 0000000..ce440b6 --- /dev/null +++ b/lib/sys/src/ffi/linux/native/.gitignore @@ -0,0 +1 @@ +# Empty gitignore to ensure the directory stays in revision control. diff --git a/lib/sys/src/ffi/linux/native/mod.rs b/lib/sys/src/ffi/linux/native/mod.rs deleted file mode 100644 index 3d6b5a5..0000000 --- a/lib/sys/src/ffi/linux/native/mod.rs +++ /dev/null @@ -1,35 +0,0 @@ -//! # Pseudo-Module for the Native Platform -//! -//! This module behaves like an alias of the platform-module that matches the -//! compilation target. However, it is not a straight alias but a recompilation -//! of the platform-module with the Rust primitives as ABI. -//! -//! If no platform-module matches the compilation target, this will use the -//! `libc` module (if enabled). If the latter is not enabled, this module will -//! be empty. - -pub use osi::ffi::abi::native as abi; - -osi::cfg::cond! { - (doc) { - #[path = "../x86_64/mod.rs"] - mod inner; - }, - (target_arch = "x86") { - #[path = "../x86/mod.rs"] - mod inner; - }, - (target_arch = "x86_64") { - #[path = "../x86_64/mod.rs"] - mod inner; - }, - (feature = "libc") { - use super::libc as inner; - }, - { - mod inner {} - }, -} - -#[allow(unused)] -pub use inner::*; diff --git a/lib/sys/src/ffi/linux/test.rs b/lib/sys/src/ffi/linux/test.rs index 4772450..dcdd643 100644 --- a/lib/sys/src/ffi/linux/test.rs +++ b/lib/sys/src/ffi/linux/test.rs @@ -2,13 +2,24 @@ //! //! This module contains tests for all exported FFI definitions of the //! `ffi::linux` module. +//! +//! Currently, tests are only run if `libc` is enabled. This simplifies the +//! test setup and allows testing against known libc values. + +#![cfg(all(test, feature = "libc"))] use super::*; -// If `libc` is not enabled, just alias it from `native` so the test -// can just use `libc` unconditionally. -#[cfg(not(feature = "libc"))] -use native as libc; +// Compare two type definitions for equality. +fn eq_def_type() -> bool { + core::mem::size_of::() == core::mem::size_of::() + && core::mem::align_of::() == core::mem::align_of::() +} + +// A 3-way variant of `eq_def_type()`. +fn eq3_def_type() -> bool { + eq_def_type::() && eq_def_type::() +} // Compare two `const` definitions for equality. This will compare their type // layout and memory content for equality. @@ -31,17 +42,180 @@ unsafe fn eq3_def_const(a: &A, b: &B, c: &C) -> bool { // they expose `abi::U16`. #[test] fn platform_availability() { + assert_eq!(core::mem::size_of::(), 2); + assert_eq!(core::mem::size_of::(), 2); assert_eq!(core::mem::size_of::(), 2); assert_eq!(core::mem::size_of::(), 2); assert_eq!(core::mem::size_of::(), 2); assert_eq!(core::mem::size_of::(), 2); - assert_eq!(core::mem::size_of::(), 2); } -// Compare target APIs with native and libc APIs, and verify they match. +// Compare ABIs of target, native, and libc. +#[test] +fn target_abi() { + assert!(eq3_def_type::()); + assert!(eq3_def_type::()); + assert!(eq3_def_type::()); + assert!(eq3_def_type::()); + assert!(eq3_def_type::()); + assert!(eq3_def_type::()); + + assert!(eq3_def_type::()); + assert!(eq3_def_type::()); + assert!(eq3_def_type::()); + assert!(eq3_def_type::()); + assert!(eq3_def_type::()); + assert!(eq3_def_type::()); + + assert!(eq3_def_type::()); + assert!(eq3_def_type::()); + + assert!(eq3_def_type::()); + assert!(eq3_def_type::, native::abi::Ptr<()>, libc::abi::Ptr<()>>()); + + // `Addr` should match `Usize` and `Ptr<()>` in layout. + assert!(eq_def_type::()); + assert!(eq_def_type::>()); +} + +// Compare errnos of target, native and libc. #[test] -fn comparison() { +fn target_errno() { unsafe { assert!(eq3_def_const(&target::errno::EPERM, &native::errno::EPERM, &libc::errno::EPERM)); + assert!(eq3_def_const(&target::errno::ENOENT, &native::errno::ENOENT, &libc::errno::ENOENT)); + assert!(eq3_def_const(&target::errno::ESRCH, &native::errno::ESRCH, &libc::errno::ESRCH)); + assert!(eq3_def_const(&target::errno::EINTR, &native::errno::EINTR, &libc::errno::EINTR)); + assert!(eq3_def_const(&target::errno::EIO, &native::errno::EIO, &libc::errno::EIO)); + assert!(eq3_def_const(&target::errno::ENXIO, &native::errno::ENXIO, &libc::errno::ENXIO)); + assert!(eq3_def_const(&target::errno::E2BIG, &native::errno::E2BIG, &libc::errno::E2BIG)); + assert!(eq3_def_const(&target::errno::ENOEXEC, &native::errno::ENOEXEC, &libc::errno::ENOEXEC)); + assert!(eq3_def_const(&target::errno::EBADF, &native::errno::EBADF, &libc::errno::EBADF)); + assert!(eq3_def_const(&target::errno::ECHILD, &native::errno::ECHILD, &libc::errno::ECHILD)); + assert!(eq3_def_const(&target::errno::EAGAIN, &native::errno::EAGAIN, &libc::errno::EAGAIN)); + assert!(eq3_def_const(&target::errno::ENOMEM, &native::errno::ENOMEM, &libc::errno::ENOMEM)); + assert!(eq3_def_const(&target::errno::EACCES, &native::errno::EACCES, &libc::errno::EACCES)); + assert!(eq3_def_const(&target::errno::EFAULT, &native::errno::EFAULT, &libc::errno::EFAULT)); + assert!(eq3_def_const(&target::errno::ENOTBLK, &native::errno::ENOTBLK, &libc::errno::ENOTBLK)); + assert!(eq3_def_const(&target::errno::EBUSY, &native::errno::EBUSY, &libc::errno::EBUSY)); + assert!(eq3_def_const(&target::errno::EEXIST, &native::errno::EEXIST, &libc::errno::EEXIST)); + assert!(eq3_def_const(&target::errno::EXDEV, &native::errno::EXDEV, &libc::errno::EXDEV)); + assert!(eq3_def_const(&target::errno::ENODEV, &native::errno::ENODEV, &libc::errno::ENODEV)); + assert!(eq3_def_const(&target::errno::ENOTDIR, &native::errno::ENOTDIR, &libc::errno::ENOTDIR)); + assert!(eq3_def_const(&target::errno::EISDIR, &native::errno::EISDIR, &libc::errno::EISDIR)); + assert!(eq3_def_const(&target::errno::EINVAL, &native::errno::EINVAL, &libc::errno::EINVAL)); + assert!(eq3_def_const(&target::errno::ENFILE, &native::errno::ENFILE, &libc::errno::ENFILE)); + assert!(eq3_def_const(&target::errno::EMFILE, &native::errno::EMFILE, &libc::errno::EMFILE)); + assert!(eq3_def_const(&target::errno::ENOTTY, &native::errno::ENOTTY, &libc::errno::ENOTTY)); + assert!(eq3_def_const(&target::errno::ETXTBSY, &native::errno::ETXTBSY, &libc::errno::ETXTBSY)); + assert!(eq3_def_const(&target::errno::EFBIG, &native::errno::EFBIG, &libc::errno::EFBIG)); + assert!(eq3_def_const(&target::errno::ENOSPC, &native::errno::ENOSPC, &libc::errno::ENOSPC)); + assert!(eq3_def_const(&target::errno::ESPIPE, &native::errno::ESPIPE, &libc::errno::ESPIPE)); + assert!(eq3_def_const(&target::errno::EROFS, &native::errno::EROFS, &libc::errno::EROFS)); + assert!(eq3_def_const(&target::errno::EMLINK, &native::errno::EMLINK, &libc::errno::EMLINK)); + assert!(eq3_def_const(&target::errno::EPIPE, &native::errno::EPIPE, &libc::errno::EPIPE)); + assert!(eq3_def_const(&target::errno::EDOM, &native::errno::EDOM, &libc::errno::EDOM)); + assert!(eq3_def_const(&target::errno::ERANGE, &native::errno::ERANGE, &libc::errno::ERANGE)); + + assert!(eq3_def_const(&target::errno::EDEADLK, &native::errno::EDEADLK, &libc::errno::EDEADLK)); + assert!(eq3_def_const(&target::errno::ENAMETOOLONG, &native::errno::ENAMETOOLONG, &libc::errno::ENAMETOOLONG)); + assert!(eq3_def_const(&target::errno::ENOLCK, &native::errno::ENOLCK, &libc::errno::ENOLCK)); + assert!(eq3_def_const(&target::errno::ENOSYS, &native::errno::ENOSYS, &libc::errno::ENOSYS)); + assert!(eq3_def_const(&target::errno::ENOTEMPTY, &native::errno::ENOTEMPTY, &libc::errno::ENOTEMPTY)); + assert!(eq3_def_const(&target::errno::ELOOP, &native::errno::ELOOP, &libc::errno::ELOOP)); + assert!(eq3_def_const(&target::errno::ENOMSG, &native::errno::ENOMSG, &libc::errno::ENOMSG)); + assert!(eq3_def_const(&target::errno::EIDRM, &native::errno::EIDRM, &libc::errno::EIDRM)); + assert!(eq3_def_const(&target::errno::ECHRNG, &native::errno::ECHRNG, &libc::errno::ECHRNG)); + assert!(eq3_def_const(&target::errno::EL2NSYNC, &native::errno::EL2NSYNC, &libc::errno::EL2NSYNC)); + assert!(eq3_def_const(&target::errno::EL3HLT, &native::errno::EL3HLT, &libc::errno::EL3HLT)); + assert!(eq3_def_const(&target::errno::EL3RST, &native::errno::EL3RST, &libc::errno::EL3RST)); + assert!(eq3_def_const(&target::errno::ELNRNG, &native::errno::ELNRNG, &libc::errno::ELNRNG)); + assert!(eq3_def_const(&target::errno::EUNATCH, &native::errno::EUNATCH, &libc::errno::EUNATCH)); + assert!(eq3_def_const(&target::errno::ENOCSI, &native::errno::ENOCSI, &libc::errno::ENOCSI)); + assert!(eq3_def_const(&target::errno::EL2HLT, &native::errno::EL2HLT, &libc::errno::EL2HLT)); + assert!(eq3_def_const(&target::errno::EBADE, &native::errno::EBADE, &libc::errno::EBADE)); + assert!(eq3_def_const(&target::errno::EBADR, &native::errno::EBADR, &libc::errno::EBADR)); + assert!(eq3_def_const(&target::errno::EXFULL, &native::errno::EXFULL, &libc::errno::EXFULL)); + assert!(eq3_def_const(&target::errno::ENOANO, &native::errno::ENOANO, &libc::errno::ENOANO)); + assert!(eq3_def_const(&target::errno::EBADRQC, &native::errno::EBADRQC, &libc::errno::EBADRQC)); + assert!(eq3_def_const(&target::errno::EBADSLT, &native::errno::EBADSLT, &libc::errno::EBADSLT)); + assert!(eq3_def_const(&target::errno::EBFONT, &native::errno::EBFONT, &libc::errno::EBFONT)); + assert!(eq3_def_const(&target::errno::ENOSTR, &native::errno::ENOSTR, &libc::errno::ENOSTR)); + assert!(eq3_def_const(&target::errno::ENODATA, &native::errno::ENODATA, &libc::errno::ENODATA)); + assert!(eq3_def_const(&target::errno::ETIME, &native::errno::ETIME, &libc::errno::ETIME)); + assert!(eq3_def_const(&target::errno::ENOSR, &native::errno::ENOSR, &libc::errno::ENOSR)); + assert!(eq3_def_const(&target::errno::ENONET, &native::errno::ENONET, &libc::errno::ENONET)); + assert!(eq3_def_const(&target::errno::ENOPKG, &native::errno::ENOPKG, &libc::errno::ENOPKG)); + assert!(eq3_def_const(&target::errno::EREMOTE, &native::errno::EREMOTE, &libc::errno::EREMOTE)); + assert!(eq3_def_const(&target::errno::ENOLINK, &native::errno::ENOLINK, &libc::errno::ENOLINK)); + assert!(eq3_def_const(&target::errno::EADV, &native::errno::EADV, &libc::errno::EADV)); + assert!(eq3_def_const(&target::errno::ESRMNT, &native::errno::ESRMNT, &libc::errno::ESRMNT)); + assert!(eq3_def_const(&target::errno::ECOMM, &native::errno::ECOMM, &libc::errno::ECOMM)); + assert!(eq3_def_const(&target::errno::EPROTO, &native::errno::EPROTO, &libc::errno::EPROTO)); + assert!(eq3_def_const(&target::errno::EMULTIHOP, &native::errno::EMULTIHOP, &libc::errno::EMULTIHOP)); + assert!(eq3_def_const(&target::errno::EDOTDOT, &native::errno::EDOTDOT, &libc::errno::EDOTDOT)); + assert!(eq3_def_const(&target::errno::EBADMSG, &native::errno::EBADMSG, &libc::errno::EBADMSG)); + assert!(eq3_def_const(&target::errno::EOVERFLOW, &native::errno::EOVERFLOW, &libc::errno::EOVERFLOW)); + assert!(eq3_def_const(&target::errno::ENOTUNIQ, &native::errno::ENOTUNIQ, &libc::errno::ENOTUNIQ)); + assert!(eq3_def_const(&target::errno::EBADFD, &native::errno::EBADFD, &libc::errno::EBADFD)); + assert!(eq3_def_const(&target::errno::EREMCHG, &native::errno::EREMCHG, &libc::errno::EREMCHG)); + assert!(eq3_def_const(&target::errno::ELIBACC, &native::errno::ELIBACC, &libc::errno::ELIBACC)); + assert!(eq3_def_const(&target::errno::ELIBBAD, &native::errno::ELIBBAD, &libc::errno::ELIBBAD)); + assert!(eq3_def_const(&target::errno::ELIBSCN, &native::errno::ELIBSCN, &libc::errno::ELIBSCN)); + assert!(eq3_def_const(&target::errno::ELIBMAX, &native::errno::ELIBMAX, &libc::errno::ELIBMAX)); + assert!(eq3_def_const(&target::errno::ELIBEXEC, &native::errno::ELIBEXEC, &libc::errno::ELIBEXEC)); + assert!(eq3_def_const(&target::errno::EILSEQ, &native::errno::EILSEQ, &libc::errno::EILSEQ)); + assert!(eq3_def_const(&target::errno::ERESTART, &native::errno::ERESTART, &libc::errno::ERESTART)); + assert!(eq3_def_const(&target::errno::ESTRPIPE, &native::errno::ESTRPIPE, &libc::errno::ESTRPIPE)); + assert!(eq3_def_const(&target::errno::EUSERS, &native::errno::EUSERS, &libc::errno::EUSERS)); + assert!(eq3_def_const(&target::errno::ENOTSOCK, &native::errno::ENOTSOCK, &libc::errno::ENOTSOCK)); + assert!(eq3_def_const(&target::errno::EDESTADDRREQ, &native::errno::EDESTADDRREQ, &libc::errno::EDESTADDRREQ)); + assert!(eq3_def_const(&target::errno::EMSGSIZE, &native::errno::EMSGSIZE, &libc::errno::EMSGSIZE)); + assert!(eq3_def_const(&target::errno::EPROTOTYPE, &native::errno::EPROTOTYPE, &libc::errno::EPROTOTYPE)); + assert!(eq3_def_const(&target::errno::ENOPROTOOPT, &native::errno::ENOPROTOOPT, &libc::errno::ENOPROTOOPT)); + assert!(eq3_def_const(&target::errno::EPROTONOSUPPORT, &native::errno::EPROTONOSUPPORT, &libc::errno::EPROTONOSUPPORT)); + assert!(eq3_def_const(&target::errno::ESOCKTNOSUPPORT, &native::errno::ESOCKTNOSUPPORT, &libc::errno::ESOCKTNOSUPPORT)); + assert!(eq3_def_const(&target::errno::EOPNOTSUPP, &native::errno::EOPNOTSUPP, &libc::errno::EOPNOTSUPP)); + assert!(eq3_def_const(&target::errno::EPFNOSUPPORT, &native::errno::EPFNOSUPPORT, &libc::errno::EPFNOSUPPORT)); + assert!(eq3_def_const(&target::errno::EAFNOSUPPORT, &native::errno::EAFNOSUPPORT, &libc::errno::EAFNOSUPPORT)); + assert!(eq3_def_const(&target::errno::EADDRINUSE, &native::errno::EADDRINUSE, &libc::errno::EADDRINUSE)); + assert!(eq3_def_const(&target::errno::EADDRNOTAVAIL, &native::errno::EADDRNOTAVAIL, &libc::errno::EADDRNOTAVAIL)); + assert!(eq3_def_const(&target::errno::ENETDOWN, &native::errno::ENETDOWN, &libc::errno::ENETDOWN)); + assert!(eq3_def_const(&target::errno::ENETUNREACH, &native::errno::ENETUNREACH, &libc::errno::ENETUNREACH)); + assert!(eq3_def_const(&target::errno::ENETRESET, &native::errno::ENETRESET, &libc::errno::ENETRESET)); + assert!(eq3_def_const(&target::errno::ECONNABORTED, &native::errno::ECONNABORTED, &libc::errno::ECONNABORTED)); + assert!(eq3_def_const(&target::errno::ECONNRESET, &native::errno::ECONNRESET, &libc::errno::ECONNRESET)); + assert!(eq3_def_const(&target::errno::ENOBUFS, &native::errno::ENOBUFS, &libc::errno::ENOBUFS)); + assert!(eq3_def_const(&target::errno::EISCONN, &native::errno::EISCONN, &libc::errno::EISCONN)); + assert!(eq3_def_const(&target::errno::ENOTCONN, &native::errno::ENOTCONN, &libc::errno::ENOTCONN)); + assert!(eq3_def_const(&target::errno::ESHUTDOWN, &native::errno::ESHUTDOWN, &libc::errno::ESHUTDOWN)); + assert!(eq3_def_const(&target::errno::ETOOMANYREFS, &native::errno::ETOOMANYREFS, &libc::errno::ETOOMANYREFS)); + assert!(eq3_def_const(&target::errno::ETIMEDOUT, &native::errno::ETIMEDOUT, &libc::errno::ETIMEDOUT)); + assert!(eq3_def_const(&target::errno::ECONNREFUSED, &native::errno::ECONNREFUSED, &libc::errno::ECONNREFUSED)); + assert!(eq3_def_const(&target::errno::EHOSTDOWN, &native::errno::EHOSTDOWN, &libc::errno::EHOSTDOWN)); + assert!(eq3_def_const(&target::errno::EHOSTUNREACH, &native::errno::EHOSTUNREACH, &libc::errno::EHOSTUNREACH)); + assert!(eq3_def_const(&target::errno::EALREADY, &native::errno::EALREADY, &libc::errno::EALREADY)); + assert!(eq3_def_const(&target::errno::EINPROGRESS, &native::errno::EINPROGRESS, &libc::errno::EINPROGRESS)); + assert!(eq3_def_const(&target::errno::ESTALE, &native::errno::ESTALE, &libc::errno::ESTALE)); + assert!(eq3_def_const(&target::errno::EUCLEAN, &native::errno::EUCLEAN, &libc::errno::EUCLEAN)); + assert!(eq3_def_const(&target::errno::ENOTNAM, &native::errno::ENOTNAM, &libc::errno::ENOTNAM)); + assert!(eq3_def_const(&target::errno::ENAVAIL, &native::errno::ENAVAIL, &libc::errno::ENAVAIL)); + assert!(eq3_def_const(&target::errno::EISNAM, &native::errno::EISNAM, &libc::errno::EISNAM)); + assert!(eq3_def_const(&target::errno::EREMOTEIO, &native::errno::EREMOTEIO, &libc::errno::EREMOTEIO)); + assert!(eq3_def_const(&target::errno::EDQUOT, &native::errno::EDQUOT, &libc::errno::EDQUOT)); + assert!(eq3_def_const(&target::errno::ENOMEDIUM, &native::errno::ENOMEDIUM, &libc::errno::ENOMEDIUM)); + assert!(eq3_def_const(&target::errno::EMEDIUMTYPE, &native::errno::EMEDIUMTYPE, &libc::errno::EMEDIUMTYPE)); + assert!(eq3_def_const(&target::errno::ECANCELED, &native::errno::ECANCELED, &libc::errno::ECANCELED)); + assert!(eq3_def_const(&target::errno::ENOKEY, &native::errno::ENOKEY, &libc::errno::ENOKEY)); + assert!(eq3_def_const(&target::errno::EKEYEXPIRED, &native::errno::EKEYEXPIRED, &libc::errno::EKEYEXPIRED)); + assert!(eq3_def_const(&target::errno::EKEYREVOKED, &native::errno::EKEYREVOKED, &libc::errno::EKEYREVOKED)); + assert!(eq3_def_const(&target::errno::EKEYREJECTED, &native::errno::EKEYREJECTED, &libc::errno::EKEYREJECTED)); + assert!(eq3_def_const(&target::errno::EOWNERDEAD, &native::errno::EOWNERDEAD, &libc::errno::EOWNERDEAD)); + assert!(eq3_def_const(&target::errno::ENOTRECOVERABLE, &native::errno::ENOTRECOVERABLE, &libc::errno::ENOTRECOVERABLE)); + assert!(eq3_def_const(&target::errno::ERFKILL, &native::errno::ERFKILL, &libc::errno::ERFKILL)); + assert!(eq3_def_const(&target::errno::EHWPOISON, &native::errno::EHWPOISON, &libc::errno::EHWPOISON)); + + assert!(eq3_def_const(&target::errno::EWOULDBLOCK, &native::errno::EWOULDBLOCK, &libc::errno::EWOULDBLOCK)); + assert!(eq3_def_const(&target::errno::EDEADLOCK, &native::errno::EDEADLOCK, &libc::errno::EDEADLOCK)); } } diff --git a/lib/sys/src/ffi/linux/x86/mod.rs b/lib/sys/src/ffi/linux/x86/mod.rs index e5acd67..f043630 100644 --- a/lib/sys/src/ffi/linux/x86/mod.rs +++ b/lib/sys/src/ffi/linux/x86/mod.rs @@ -1,6 +1,6 @@ // Platform Module for x86 // -// This module is included multiple times by `../../linux.rs`, using outer +// This module is included multiple times by `../mod.rs`, using outer // comments for documentation. It is also the responsibility of the caller // to define the ABI to use. This module simply re-uses it via // `use super::abi`. diff --git a/lib/sys/src/ffi/linux/x86_64/mod.rs b/lib/sys/src/ffi/linux/x86_64/mod.rs index a7bb7fc..100719d 100644 --- a/lib/sys/src/ffi/linux/x86_64/mod.rs +++ b/lib/sys/src/ffi/linux/x86_64/mod.rs @@ -1,6 +1,6 @@ // Platform Module for x86_64 // -// This module is included multiple times by `../../linux.rs`, using outer +// This module is included multiple times by `../mod.rs`, using outer // comments for documentation. It is also the responsibility of the caller // to define the ABI to use. This module simply re-uses it via // `use super::abi`. diff --git a/lib/sys/src/ffi/mod.rs b/lib/sys/src/ffi/mod.rs new file mode 100644 index 0000000..ddfedb1 --- /dev/null +++ b/lib/sys/src/ffi/mod.rs @@ -0,0 +1,73 @@ +//! # Definitions of System Interfaces +//! +//! For all system interfaces the respective raw definitions of constants, +//! structures, types, and more are provided in this module. This allows use of +//! these definitions outside of possible higher abstractions. +//! +//! The definitions are transposed into Rust following a set of rules and +//! guidelines, thus yielding predictable type names and definitions. The idea +//! is to produce the same predictable result, as if a tool like `bindgen` +//! was used. +//! +//! This module only provides the definitions of the system interfaces, but no +//! implementation. This is left to other modules (or the user). +//! +//! ## Transpose Rules +//! +//! While this module attempts to be a direct mapping to the respective +//! protocols and specifications, slight adjustments are usually necessary to +//! account for the peculiarities of Rust: +//! +//! * All names follow the standard Rust naming scheme, using `CamelCase` for +//! types, `UPPER_CASE` for constants, and `snake_case` for everything else. +//! +//! * Prefixes are stripped if the Rust module or type-system provides a +//! suitable prefix. +//! +//! * C-enums are always provided as raw integer type, rather than Rust enum +//! to allow arbitrary discriminants to be used. This is particularly +//! important when the interface allows for custom/vendor extensions, since +//! then Rust enums would be unable to represent the unused ranges. +//! +//! * Pointers are always represented as `NonNull` or `Option` and +//! thus strip any `const` annotations. This is on purpose, since the +//! classic C-const annotations cannot be transposed to Rust in a sensible +//! way. For architecture-independent representations, see `osi::ffi`. +//! +//! * `no incomplete types`: Several structures use incomplete structure types +//! by using an unbound array as last member. While rust can easily +//! represent those within its type-system, such structures become DSTs, +//! hence even raw pointers to them become fat-pointers, and would thus +//! violate the UEFI ABI. +//! +//! Instead, we use const-generics to allow compile-time adjustment of the +//! variable-sized structures, with a default value of 0. This allows +//! computing different sizes of the structures without any runtime +//! overhead. +//! +//! ## Foreign Architectures +//! +//! Generally, definitions are provided in an architecture independent format. +//! This means, the structures and definitions will be the same regardless of +//! the compilation target platform. This allows accessing definitions of +//! foreign architectures without any extra care (e.g., inspecting core dumps +//! of another machine). Unfortunately, this makes most primitive types +//! unsuitable for those definitions. Therefore, some aliases are provided, if +//! possible. +//! +//! If an FFI module is specific to an architecture, it is provided once for +//! each architecture, using the ABI of the respective architecture. +//! Additionally, is is also provided as a module called _"native"_, using the +//! compiler primitives. This _"native"_ module is only provided if the FFI +//! module is available for the target platform. +//! +//! For instance, `ffi::linux` exposes the linux definitions for each +//! architecture separately (e.g., `ffi::linux::x86`), but provides +//! `ffi::linux::native` as an alias using native compiler primitives. +//! +//! If an FFI module is otherwise specific to a given property, a similar style +//! is followed. However, if the number of options is fixed, it might be used +//! as suffix instead (e.g., `elf32`, `elf64`, `elfn`, where the latter is the +//! equivalent of _"native"_). + +pub mod linux; diff --git a/lib/sys/src/linux.rs b/lib/sys/src/linux/mod.rs similarity index 84% rename from lib/sys/src/linux.rs rename to lib/sys/src/linux/mod.rs index 619fe36..fdc42fb 100644 --- a/lib/sys/src/linux.rs +++ b/lib/sys/src/linux/mod.rs @@ -1,4 +1,4 @@ -//! Linux System Interfaces +//! # Linux System Interfaces //! //! This module provides access to Linux system interfaces provided by the //! kernel and common across all Linux systems. From e0f4f8f2e6208bbfeb2f7135a7fe3cba57ef2c6f Mon Sep 17 00:00:00 2001 From: David Rheinsberg Date: Mon, 27 Apr 2026 13:36:38 +0200 Subject: [PATCH 06/10] doc: fix rustdoc references Fix a couple of rustdoc references, which are either redundant, unresolved, or not available in no_std. Signed-off-by: David Rheinsberg --- lib/osi/src/mem.rs | 22 ++++++++++------------ lib/osi/src/mown.rs | 3 +-- lib/tmp/src/io/stream.rs | 4 ++-- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/lib/osi/src/mem.rs b/lib/osi/src/mem.rs index 4272920..45c00a9 100644 --- a/lib/osi/src/mem.rs +++ b/lib/osi/src/mem.rs @@ -160,7 +160,7 @@ pub const unsafe fn bswap_copy(v: &T) -> T { } } -/// Alias a type as a [`MaybeUninit`](core::mem::MaybeUninit). +/// Alias a type as a [`Uninit`]. /// /// Any type can be aliased as a possibly uninitialized type. This is usually /// only necessary when providing initialized data to code that can handle @@ -171,7 +171,7 @@ pub const fn as_uninit(v: &T) -> &Uninit { } } -/// Alias a slice as a [`MaybeUninit`](core::mem::MaybeUninit). +/// Alias a slice as a [`Uninit`]. /// /// This works like [`as_uninit()`] but for slices of `T`. pub const fn slice_as_uninit(v: &[T]) -> &[Uninit] { @@ -180,11 +180,11 @@ pub const fn slice_as_uninit(v: &[T]) -> &[Uninit] { } } -/// Alias a [`MaybeUninit`](core::mem::MaybeUninit) type as initialized. +/// Alias a [`Uninit`] type as initialized. /// /// ## Safety /// -/// It is up to the caller to guarantee that the [`MaybeUninit`] really is +/// It is up to the caller to guarantee that the [`Uninit`] really is /// in an initialized state. Calling this when the content is not yet fully /// initialized causes immediate undefined behavior. pub const unsafe fn assume_init(v: &Uninit) -> &T { @@ -193,12 +193,11 @@ pub const unsafe fn assume_init(v: &Uninit) -> &T { } } -/// Mutably alias a [`MaybeUninit`](core::mem::MaybeUninit) type as -/// initialized. +/// Mutably alias a [`Uninit`] type as initialized. /// /// ## Safety /// -/// It is up to the caller to guarantee that the [`MaybeUninit`] really is +/// It is up to the caller to guarantee that the [`Uninit`] really is /// in an initialized state. Calling this when the content is not yet fully /// initialized causes immediate undefined behavior. pub const unsafe fn assume_init_mut(v: &mut Uninit) -> &mut T { @@ -207,11 +206,11 @@ pub const unsafe fn assume_init_mut(v: &mut Uninit) -> &mut T { } } -/// Alias a slice of [`MaybeUninit`](core::mem::MaybeUninit) as initialized. +/// Alias a slice of [`Uninit`] as initialized. /// /// ## Safety /// -/// It is up to the caller to guarantee that the [`MaybeUninit`] really is +/// It is up to the caller to guarantee that the [`Uninit`] really is /// in an initialized state. Calling this when the content is not yet fully /// initialized causes immediate undefined behavior. pub const unsafe fn slice_assume_init(v: &[Uninit]) -> &[T] { @@ -220,12 +219,11 @@ pub const unsafe fn slice_assume_init(v: &[Uninit]) -> &[T] { } } -/// Mutably alias a slice of [`MaybeUninit`](core::mem::MaybeUninit) as -/// initialized. +/// Mutably alias a slice of [`Uninit`] as initialized. /// /// ## Safety /// -/// It is up to the caller to guarantee that the [`MaybeUninit`] really is +/// It is up to the caller to guarantee that the [`Uninit`] really is /// in an initialized state. Calling this when the content is not yet fully /// initialized causes immediate undefined behavior. pub const unsafe fn slice_assume_init_mut(v: &mut [Uninit]) -> &mut [T] { diff --git a/lib/osi/src/mown.rs b/lib/osi/src/mown.rs index 184a786..52264a7 100644 --- a/lib/osi/src/mown.rs +++ b/lib/osi/src/mown.rs @@ -15,8 +15,7 @@ /// ## Similarity to Cow /// /// This type is almost identical to [`Cow`](alloc::borrow::Cow), but does not -/// require [`Clone`](core::clone::Clone) or any kind of support for -/// mutability. +/// require [`Clone`] or any kind of support for mutability. pub enum Mown<'a, B: ?Sized, O = &'a B> { Borrowed(&'a B), Owned(O), diff --git a/lib/tmp/src/io/stream.rs b/lib/tmp/src/io/stream.rs index a76f4e1..102672b 100644 --- a/lib/tmp/src/io/stream.rs +++ b/lib/tmp/src/io/stream.rs @@ -31,7 +31,7 @@ pub struct More { /// layers. That is, it allows writing code that reads structured data from a /// data stream without knowing the transport layer used to stream the data. /// -/// The trait is similar to [`std::io::Read`] but is designed for buffered +/// The trait is similar to `std::io::Read` but is designed for buffered /// streams that perform transport layer operations /// /// The actual transport layer operations are not part of this trait, but must @@ -78,7 +78,7 @@ pub trait Read { /// layers. That is, it allows writing code that writes structured data to a /// data stream without knowing the transport layer used to stream the data. /// -/// The trait is similar to [`std::io::Write`] but is designed for buffered +/// The trait is similar to `std::io::Write` but is designed for buffered /// streams that perform transport layer operations /// /// The actual transport layer operations are not part of this trait, but must From 992e9429ce0827d3fa0da80462bdae7402ddd9d7 Mon Sep 17 00:00:00 2001 From: David Rheinsberg Date: Tue, 28 Apr 2026 09:32:10 +0200 Subject: [PATCH 07/10] sys/ffi: fix doc header Use a proper module doc header. Signed-off-by: David Rheinsberg --- lib/sys/src/ffi/linux/common/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sys/src/ffi/linux/common/mod.rs b/lib/sys/src/ffi/linux/common/mod.rs index 69c5ed5..a624048 100644 --- a/lib/sys/src/ffi/linux/common/mod.rs +++ b/lib/sys/src/ffi/linux/common/mod.rs @@ -1,4 +1,4 @@ -// Common Linux Definitions +// # Common Linux Definitions // // This module provides a common implementation of the vast majority of Linux // system interfaces. It is meant to be used by the platform-modules via: From 08ffe516fbca88602335ce4a73ef1347ddbda80d Mon Sep 17 00:00:00 2001 From: David Rheinsberg Date: Tue, 28 Apr 2026 09:42:48 +0200 Subject: [PATCH 08/10] sys/ffi: add elf module Add sys::ffi::elf with common definitions of the executable and linkable format. Signed-off-by: David Rheinsberg --- lib/sys/src/ffi/elf.rs | 978 +++++++++++++++++++++++++++++++++++++++++ lib/sys/src/ffi/mod.rs | 1 + 2 files changed, 979 insertions(+) create mode 100644 lib/sys/src/ffi/elf.rs diff --git a/lib/sys/src/ffi/elf.rs b/lib/sys/src/ffi/elf.rs new file mode 100644 index 0000000..df7364c --- /dev/null +++ b/lib/sys/src/ffi/elf.rs @@ -0,0 +1,978 @@ +//! # Definitions of the Executable and Linkable Format +//! +//! This module provides the definitions of the Executable and Linkable Format +//! (ELF) as native Rust types. It is a transpose of the reference definitions +//! in C to Rust. Please consult an ELF specification for usage information. +//! This module merely documents the differences to the reference specification +//! and how it applies to Rust. +//! +//! Note that this module is a pure import of the definitions from the +//! specification with **NO** accompanying implementation. It is suitable for +//! use in dynamic loaders and other software running in highly constrained +//! environments. +//! +//! The module is available as 32-bit and 64-bit version. Additionally, the +//! `elfn` alias refers to the module native to the target platform. +//! +//! ## Basic Types +//! +//! The ELF basic types (`Addr`, `Off`, `Half`, `Word`, ...) are not +//! provided. Their alignment requirements match their size, and thus there +//! are no suitable native integer types when accessing cross-platform ELF +//! files (e.g., `u64` on a 32bit machine would be 4-byte aligned rather than +//! 8-bytes aligned). Furthermore, terms like `Word` and `Half(-word)` have +//! lost meaning over the years and explicitly sized integers are preferred. +//! Hence, we recommend using native integer types directly. +//! +//! ## References +//! +//! Generic ABI (gABI) Specifications: +//! +//! - Published by SCO and generally most applicable: +//! +//! - Published by Oracle and mostly for Solaris: +//! +//! +//! Platform Specific ABI (psABI) Specifications: +//! +//! - i386 as published by the Linux Foundation: +//! +//! - x86_64 as published by the Linux Foundation: +//! +//! +//! Specification Registries: +//! +//! - uclibc maintained registry: +//! +//! - Linux Foundation Reference Specifications: +//! + +mod common { + pub const ELFMAG0: u8 = 0x7f; + pub const ELFMAG1: u8 = b'E'; + pub const ELFMAG2: u8 = b'L'; + pub const ELFMAG3: u8 = b'F'; + + pub const ELFMAG: [u8; 4] = [ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3]; + + pub const ELFCLASSNONE: u8 = 0; + pub const ELFCLASS32: u8 = 1; + pub const ELFCLASS64: u8 = 2; + + pub const ELFDATANONE: u8 = 0; + pub const ELFDATA2LSB: u8 = 1; + pub const ELFDATA2MSB: u8 = 2; + + pub const ELFOSABI_NONE: u8 = 0; + pub const ELFOSABI_SYSV: u8 = ELFOSABI_NONE; + pub const ELFOSABI_HPUX: u8 = 1; + pub const ELFOSABI_NETBSD: u8 = 2; + pub const ELFOSABI_GNU: u8 = 3; + pub const ELFOSABI_LINUX: u8 = ELFOSABI_GNU; + pub const ELFOSABI_HURD: u8 = 4; + pub const ELFOSABI_86OPEN: u8 = 5; + pub const ELFOSABI_SOLARIS: u8 = 6; + pub const ELFOSABI_AIX: u8 = 7; + pub const ELFOSABI_MONTEREY: u8 = ELFOSABI_AIX; + pub const ELFOSABI_IRIX: u8 = 8; + pub const ELFOSABI_FREEBSD: u8 = 9; + pub const ELFOSABI_TRU64: u8 = 10; + pub const ELFOSABI_MODESTO: u8 = 11; + pub const ELFOSABI_OPENBSD: u8 = 12; + pub const ELFOSABI_OPENVMS: u8 = 13; + pub const ELFOSABI_NSK: u8 = 14; + pub const ELFOSABI_AROS: u8 = 15; + pub const ELFOSABI_FENIXOS: u8 = 16; + pub const ELFOSABI_CLOUDABI: u8 = 17; + pub const ELFOSABI_OPENVOS: u8 = 18; + pub const ELFOSABI_ARM_AEABI: u8 = 64; + pub const ELFOSABI_ARM: u8 = 97; + pub const ELFOSABI_STANDALONE: u8 = 255; + + pub const ET_NONE: u16 = 0; + pub const ET_REL: u16 = 1; + pub const ET_EXEC: u16 = 2; + pub const ET_DYN: u16 = 3; + pub const ET_CORE: u16 = 4; + pub const ET_LOOS: u16 = 0xfe00; + pub const ET_HIOS: u16 = 0xfeff; + pub const ET_LOPROC: u16 = 0xff00; + pub const ET_HIPROC: u16 = 0xffff; + + pub const EM_NONE: u16 = 0; + pub const EM_M32: u16 = 1; + pub const EM_SPARC: u16 = 2; + pub const EM_386: u16 = 3; + pub const EM_68K: u16 = 4; + pub const EM_88K: u16 = 5; + pub const EM_IAMCU: u16 = 6; + pub const EM_486: u16 = EM_IAMCU; // from: linux + pub const EM_860: u16 = 7; + pub const EM_MIPS: u16 = 8; + pub const EM_S370: u16 = 9; + pub const EM_MIPS_RS3_LE: u16 = 10; + pub const EM_MIPS_RS4_BE: u16 = EM_MIPS_RS3_LE; // from: linux + pub const EM_PARISC: u16 = 15; + pub const EM_VPP500: u16 = 17; + pub const EM_SPARC32PLUS: u16 = 18; + pub const EM_960: u16 = 19; + pub const EM_PPC: u16 = 20; + pub const EM_PPC64: u16 = 21; + pub const EM_S390: u16 = 22; + pub const EM_SPU: u16 = 23; + pub const EM_V800: u16 = 36; + pub const EM_FR20: u16 = 37; + pub const EM_RH32: u16 = 38; + pub const EM_RCE: u16 = 39; + pub const EM_ARM: u16 = 40; + pub const EM_ALPHA: u16 = 41; + pub const EM_ALPHA_STD: u16 = EM_ALPHA; // from: linux + pub const EM_SH: u16 = 42; + pub const EM_SPARCV9: u16 = 43; + pub const EM_TRICORE: u16 = 44; + pub const EM_ARC: u16 = 45; + pub const EM_H8_300: u16 = 46; + pub const EM_H8_300H: u16 = 47; + pub const EM_H8S: u16 = 48; + pub const EM_H8_500: u16 = 49; + pub const EM_IA_64: u16 = 50; + pub const EM_MIPS_X: u16 = 51; + pub const EM_COLDFIRE: u16 = 52; + pub const EM_68HC12: u16 = 53; + pub const EM_MMA: u16 = 54; + pub const EM_PCP: u16 = 55; + pub const EM_NCPU: u16 = 56; + pub const EM_NDR1: u16 = 57; + pub const EM_STARCORE: u16 = 58; + pub const EM_ME16: u16 = 59; + pub const EM_ST100: u16 = 60; + pub const EM_TINYJ: u16 = 61; + pub const EM_X86_64: u16 = 62; + pub const EM_AMD64: u16 = EM_X86_64; // from: bionic + pub const EM_PDSP: u16 = 63; + pub const EM_PDP10: u16 = 64; + pub const EM_PDP11: u16 = 65; + pub const EM_FX66: u16 = 66; + pub const EM_ST9PLUS: u16 = 67; + pub const EM_ST7: u16 = 68; + pub const EM_68HC16: u16 = 69; + pub const EM_68HC11: u16 = 70; + pub const EM_68HC08: u16 = 71; + pub const EM_68HC05: u16 = 72; + pub const EM_SVX: u16 = 73; + pub const EM_ST19: u16 = 74; + pub const EM_VAX: u16 = 75; + pub const EM_CRIS: u16 = 76; + pub const EM_JAVELIN: u16 = 77; + pub const EM_FIREPATH: u16 = 78; + pub const EM_ZSP: u16 = 79; + pub const EM_MMIX: u16 = 80; + pub const EM_HUANY: u16 = 81; + pub const EM_PRISM: u16 = 82; + pub const EM_AVR: u16 = 83; + pub const EM_FR30: u16 = 84; + pub const EM_D10V: u16 = 85; + pub const EM_D30V: u16 = 86; + pub const EM_V850: u16 = 87; + pub const EM_M32R: u16 = 88; + pub const EM_MN10300: u16 = 89; + pub const EM_MN10200: u16 = 90; + pub const EM_PJ: u16 = 91; + pub const EM_OPENRISC: u16 = 92; + pub const EM_ARC_COMPACT: u16 = 93; + pub const EM_XTENSA: u16 = 94; + pub const EM_VIDEOCORE: u16 = 95; + pub const EM_TMM_GPP: u16 = 96; + pub const EM_NS32K: u16 = 97; + pub const EM_TPC: u16 = 98; + pub const EM_SNP1K: u16 = 99; + pub const EM_ST200: u16 = 100; + pub const EM_IP2K: u16 = 101; + pub const EM_MAX: u16 = 102; + pub const EM_CR: u16 = 103; + pub const EM_F2MC16: u16 = 104; + pub const EM_MSP430: u16 = 105; + pub const EM_BLACKFIN: u16 = 106; + pub const EM_SE_C33: u16 = 107; + pub const EM_SEP: u16 = 108; + pub const EM_ARCA: u16 = 109; + pub const EM_UNICORE: u16 = 110; + pub const EM_EXCESS: u16 = 111; + pub const EM_DXP: u16 = 112; + pub const EM_ALTERA_NIOS2: u16 = 113; + pub const EM_CRX: u16 = 114; + pub const EM_XGATE: u16 = 115; + pub const EM_C166: u16 = 116; + pub const EM_M16C: u16 = 117; + pub const EM_DSPIC30F: u16 = 118; + pub const EM_CE: u16 = 119; + pub const EM_M32C: u16 = 120; + pub const EM_TSK3000: u16 = 131; + pub const EM_RS08: u16 = 132; + pub const EM_SHARC: u16 = 133; + pub const EM_ECOG2: u16 = 134; + pub const EM_SCORE7: u16 = 135; + pub const EM_DSP24: u16 = 136; + pub const EM_VIDEOCORE3: u16 = 137; + pub const EM_LATTICEMICO32: u16 = 138; + pub const EM_SE_C17: u16 = 139; + pub const EM_TI_C6000: u16 = 140; + pub const EM_TI_C2000: u16 = 141; + pub const EM_TI_C5500: u16 = 142; + pub const EM_TI_ARP32: u16 = 143; + pub const EM_TI_PRU: u16 = 144; + pub const EM_MMDSP_PLUS: u16 = 160; + pub const EM_CYPRESS_M8C: u16 = 161; + pub const EM_R32C: u16 = 162; + pub const EM_TRIMEDIA: u16 = 162; + pub const EM_QDSP6: u16 = 163; + pub const EM_8051: u16 = 164; + pub const EM_STXP7X: u16 = 165; + pub const EM_NDS32: u16 = 166; + pub const EM_ECOG1: u16 = 167; + pub const EM_ECOG1X: u16 = 168; + pub const EM_MAXQ30: u16 = 169; + pub const EM_XIMO16: u16 = 170; + pub const EM_MANIK: u16 = 171; + pub const EM_CRAYNV2: u16 = 172; + pub const EM_RX: u16 = 173; + pub const EM_METAG: u16 = 174; + pub const EM_MCST_ELBRUS: u16 = 175; + pub const EM_ECOG16: u16 = 176; + pub const EM_CR16: u16 = 177; + pub const EM_ETPU: u16 = 178; + pub const EM_SLE9X: u16 = 179; + pub const EM_L10M: u16 = 180; + pub const EM_K10M: u16 = 181; + pub const EM_AARCH64: u16 = 183; + pub const EM_AVR32: u16 = 185; + pub const EM_STM8: u16 = 186; + pub const EM_TILE64: u16 = 187; + pub const EM_TILEPRO: u16 = 188; + pub const EM_MICROBLAZE: u16 = 189; + pub const EM_CUDA: u16 = 190; + pub const EM_TILEGX: u16 = 191; + pub const EM_CLOUDSHIELD: u16 = 192; + pub const EM_COREA_1ST: u16 = 193; + pub const EM_COREA_2ND: u16 = 194; + pub const EM_ARC_COMPACT2: u16 = 195; + pub const EM_OPEN8: u16 = 196; + pub const EM_RL78: u16 = 197; + pub const EM_VIDEOCORE5: u16 = 198; + pub const EM_78KOR: u16 = 199; + pub const EM_56800EX: u16 = 200; + pub const EM_BA1: u16 = 201; + pub const EM_BA2: u16 = 202; + pub const EM_XCORE: u16 = 203; + pub const EM_MCHP_PIC: u16 = 204; + pub const EM_INTEL205: u16 = 205; + pub const EM_INTEL206: u16 = 206; + pub const EM_INTEL207: u16 = 207; + pub const EM_INTEL208: u16 = 208; + pub const EM_INTEL209: u16 = 209; + pub const EM_KM32: u16 = 210; + pub const EM_KMX32: u16 = 211; + pub const EM_KMX16: u16 = 212; + pub const EM_KMX8: u16 = 213; + pub const EM_KVARC: u16 = 214; + pub const EM_CDP: u16 = 215; + pub const EM_COGE: u16 = 216; + pub const EM_COOL: u16 = 217; + pub const EM_NORC: u16 = 218; + pub const EM_CSR_KALIMBA: u16 = 219; + pub const EM_Z80: u16 = 220; + pub const EM_VISIUM: u16 = 221; + pub const EM_FT32: u16 = 222; + pub const EM_MOXIE: u16 = 223; + pub const EM_AMDGPU: u16 = 224; + pub const EM_RISCV: u16 = 243; + pub const EM_BPF: u16 = 247; // from: linux + pub const EM_CSKY: u16 = 252; // from: linux + pub const EM_ARCV3_32: u16 = 255; // from: uclibc-ng + pub const EM_KVX: u16 = 256; // from: uclibc-ng + pub const EM_LOONGARCH: u16 = 258; // from: linux + pub const EM_AVR_INTERIM: u16 = 0x1057; // from: uclibc-ng + pub const EM_MSP430_INTERIM: u16 = 0x1059; // from: uclibc-ng + pub const EM_AVR32_INTERIM: u16 = 0x18ad; // from: uclibc-ng + pub const EM_MT_INTERIM: u16 = 0x2530; // from: uclibc-ng + pub const EM_CYGNUS_FR30_INTERIM: u16 = 0x3330; // from: uclibc-ng + pub const EM_OPENRISC_INTERIM: u16 = 0x3426; // from: uclibc-ng + pub const EM_FRV_INTERIM: u16 = 0x5441; // from: linux + pub const EM_CYGNUS_FRV_INTERIM: u16 = EM_FRV_INTERIM; // from: uclibc-ng + pub const EM_DLX_INTERIM: u16 = 0x5aa5; // from: uclibc-ng + pub const EM_CYGNUS_D10V_INTERIM: u16 = 0x7650; // from: uclibc-ng + pub const EM_CYGNUS_D30V_INTERIM: u16 = 0x7676; // from: uclibc-ng + pub const EM_IP2K_INTERIM: u16 = 0x8217; // from: uclibc-ng + pub const EM_OR32_INTERIM: u16 = 0x8472; // from: uclibc-ng + pub const EM_CYGNUS_POWERPC_INTERIM: u16 = 0x9025; // from: uclibc-ng + pub const EM_ALPHA_INTERIM: u16 = 0x9026; // from: linux + pub const EM_CYGNUS_M32R_INTERIM: u16 = 0x9041; // from: linux + pub const EM_CYGNUS_V850_INTERIM: u16 = 0x9080; // from: uclibc-ng + pub const EM_S390_INTERIM: u16 = 0xa390; // from: linux + pub const EM_XTENSA_INTERIM: u16 = 0xabc7; // from: uclibc-ng + pub const EM_XSTORMY16_INTERIM: u16 = 0xad45; // from: uclibc-ng + pub const EM_CYGNUS_MN10300_INTERIM: u16 = 0xbeef; // from: linux + pub const EM_CYGNUS_MN10200_INTERIM: u16 = 0xdead; // from: uclibc-ng + pub const EM_M32C_INTERIM: u16 = 0xfeb8; // from: uclibc-ng + pub const EM_IQ2000_INTERIM: u16 = 0xfeba; // from: uclibc-ng + pub const EM_NIOS32_INTERIM: u16 = 0xfebb; // from: uclibc-ng + + pub const EV_NONE: u8 = 0; + pub const EV_CURRENT: u8 = 1; + + pub const SHN_UNDEF: u16 = 0; + pub const SHN_LORESERVE: u16 = 0xff00; + pub const SHN_LOPROC: u16 = 0xff00; + pub const SHN_BEFORE: u16 = 0xff00; // from: solaris + pub const SHN_AFTER: u16 = 0xff01; // from: solaris + pub const SHN_HIPROC: u16 = 0xff1f; + pub const SHN_LOOS: u16 = 0xff20; + pub const SHN_FBSD_CACHED: u16 = 0xff20; // from: bionic + pub const SHN_LIVEPATCH: u16 = 0xff20; // from: linux + pub const SHN_HIOS: u16 = 0xff3f; + pub const SHN_ABS: u16 = 0xfff1; + pub const SHN_COMMON: u16 = 0xfff2; + pub const SHN_XINDEX: u16 = 0xffff; + pub const SHN_HIRESERVE: u16 = 0xffff; + + pub const SHN_LOSUNW: u16 = 0xff3f; + pub const SHN_SUNW_IGNORE: u16 = 0xff3f; + pub const SHN_HISUNW: u16 = 0xff3f; + + pub const SHN_AMD64_LCOMMON: u16 = 0xff02; // from: oracle + + pub const SHT_NULL: u32 = 0; + pub const SHT_PROGBITS: u32 = 1; + pub const SHT_SYMTAB: u32 = 2; + pub const SHT_STRTAB: u32 = 3; + pub const SHT_RELA: u32 = 4; + pub const SHT_HASH: u32 = 5; + pub const SHT_DYNAMIC: u32 = 6; + pub const SHT_NOTE: u32 = 7; + pub const SHT_NOBITS: u32 = 8; + pub const SHT_REL: u32 = 9; + pub const SHT_SHLIB: u32 = 10; + pub const SHT_DYNSYM: u32 = 11; + pub const SHT_INIT_ARRAY: u32 = 14; + pub const SHT_FINI_ARRAY: u32 = 15; + pub const SHT_PREINIT_ARRAY: u32 = 16; + pub const SHT_GROUP: u32 = 17; + pub const SHT_SYMTAB_SHNDX: u32 = 18; + pub const SHT_RELR: u32 = 19; // from: glibc + pub const SHT_LOOS: u32 = 0x60000000; + pub const SHT_CHECKSUM: u32 = 0x6ffffff8; // from: uclibc-ng + pub const SHT_HIOS: u32 = 0x6fffffff; + pub const SHT_LOPROC: u32 = 0x70000000; + pub const SHT_HIPROC: u32 = 0x7fffffff; + pub const SHT_LOUSER: u32 = 0x80000000; + pub const SHT_HIUSER: u32 = 0xffffffff; + + pub const SHT_LOGNU: u32 = 0x6ffffff5; + pub const SHT_GNU_ATTRIBUTES: u32 = 0x6ffffff5; + pub const SHT_GNU_HASH: u32 = 0x6ffffff6; + pub const SHT_GNU_LIBLIST: u32 = 0x6ffffff7; + pub const SHT_GNU_VERDEF: u32 = 0x6ffffffd; + pub const SHT_GNU_VERNEED: u32 = 0x6ffffffe; + pub const SHT_GNU_VERSYM: u32 = 0x6fffffff; + pub const SHT_HIGNU: u32 = 0x6fffffff; + + pub const SHT_LOSUNW: u32 = 0x6fffffef; + pub const SHT_SUNW_CAPCHAIN: u32 = 0x6fffffef; + pub const SHT_SUNW_CAPINFO: u32 = 0x6ffffff0; + pub const SHT_SUNW_SYMSORT: u32 = 0x6ffffff1; + pub const SHT_SUNW_TLSSORT: u32 = 0x6ffffff2; + pub const SHT_SUNW_LDYNSYM: u32 = 0x6ffffff3; + pub const SHT_SUNW_DOF: u32 = 0x6ffffff4; + pub const SHT_SUNW_CAP: u32 = 0x6ffffff5; + pub const SHT_SUNW_SIGNATURE: u32 = 0x6ffffff6; + pub const SHT_SUNW_ANNOTATE: u32 = 0x6ffffff7; + pub const SHT_SUNW_DEBUGSTR: u32 = 0x6ffffff8; + pub const SHT_SUNW_DEBUG: u32 = 0x6ffffff9; + pub const SHT_SUNW_MOVE: u32 = 0x6ffffffa; + pub const SHT_SUNW_COMDAT: u32 = 0x6ffffffb; + pub const SHT_SUNW_SYMINFO: u32 = 0x6ffffffc; + pub const SHT_SUNW_VERDEF: u32 = 0x6ffffffd; + pub const SHT_SUNW_VERNEED: u32 = 0x6ffffffe; + pub const SHT_SUNW_VERSYM: u32 = 0x6fffffff; + pub const SHT_HISUNW: u32 = 0x6fffffff; + + pub const SHT_AMD64_UNWIND: u32 = 0x70000001; // from: oracle + + pub const SHT_SPARC_GOTDATA: u32 = 0x70000000; // from: oracle + + pub const SHF_WRITE: u32 = 0x00000001; + pub const SHF_ALLOC: u32 = 0x00000002; + pub const SHF_EXECINSTR: u32 = 0x00000004; + pub const SHF_MERGE: u32 = 0x00000010; + pub const SHF_STRINGS: u32 = 0x00000020; + pub const SHF_INFO_LINK: u32 = 0x00000040; + pub const SHF_LINK_ORDER: u32 = 0x00000080; + pub const SHF_OS_NONCONFORMING: u32 = 0x00000100; + pub const SHF_GROUP: u32 = 0x00000200; + pub const SHF_TLS: u32 = 0x00000400; + pub const SHF_COMPRESSED: u32 = 0x00000800; + pub const SHF_RELA_LIVEPATCH: u32 = 0x00100000; // from: linux + pub const SHF_RO_AFTER_INIT: u32 = 0x00200000; // from: linux + pub const SHF_GNU_RETAIN: u32 = 0x00200000; // from: glibc + pub const SHF_ORDERED: u32 = 0x40000000; // from: solaris + pub const SHF_EXCLUDE: u32 = 0x80000000; // from: solaris + pub const SHF_MASKOS: u32 = 0x0ff00000; + pub const SHF_MASKPROC: u32 = 0xf0000000; + + pub const SHF_AMD64_LARGE: u32 = 0x10000000; // from: oracle + + pub const PT_NULL: u32 = 0; + pub const PT_LOAD: u32 = 1; + pub const PT_DYNAMIC: u32 = 2; + pub const PT_INTERP: u32 = 3; + pub const PT_NOTE: u32 = 4; + pub const PT_SHLIB: u32 = 5; + pub const PT_PHDR: u32 = 6; + pub const PT_TLS: u32 = 7; + pub const PT_LOOS: u32 = 0x60000000; + pub const PT_SUNW_UNWIND: u32 = 0x6464e550; // from: oracle + pub const PT_SUNW_EH_FRAME: u32 = 0x6474e550; // from: oracle + pub const PT_PAX_FLAGS: u32 = 0x65041580; // from: uclibc-ng + pub const PT_DUMP_DELTA: u32 = 0x6fb5d000; // from: bionic + pub const PT_HIOS: u32 = 0x6fffffff; + pub const PT_LOPROC: u32 = 0x70000000; + pub const PT_HIPROC: u32 = 0x7fffffff; + + pub const PT_LOGNU: u32 = 0x6474e550; + pub const PT_GNU_EH_FRAME: u32 = 0x6474e550; // from: glibc + pub const PT_GNU_STACK: u32 = 0x6474e551; // from: glibc + pub const PT_GNU_RELRO: u32 = 0x6474e552; // from: glibc + pub const PT_GNU_PROPERTY: u32 = 0x6474e553; // from: glibc + pub const PT_GNU_SFRAME: u32 = 0x6474e554; // from: glibc + pub const PT_HIGNU: u32 = 0x6474e554; + + pub const PT_LOOPENBSD: u32 = 0x65a3dbe6; + pub const PT_OPENBSD_RANDOMIZE: u32 = 0x65a3dbe6; // from: bionic + pub const PT_OPENBSD_WXNEEDED: u32 = 0x65a3dbe7; // from: bionic + pub const PT_OPENBSD_BOOTDATA: u32 = 0x65a41be6; // from: bionic + pub const PT_HIOPENBSD: u32 = 0x65a41be6; + + pub const PT_LOSUNW: u32 = 0x6ffffffa; // from: oracle + pub const PT_SUNWBSS: u32 = 0x6ffffffa; // from: oracle + pub const PT_SUNWSTACK: u32 = 0x6ffffffb; // from: oracle + pub const PT_SUNWDTRACE: u32 = 0x6ffffffc; // from: oracle + pub const PT_SUNWCAP: u32 = 0x6ffffffd; // from: oracle + pub const PT_HISUNW: u32 = 0x6fffffff; // from: oracle + + pub const PF_X: u32 = 0x00000001; + pub const PF_W: u32 = 0x00000002; + pub const PF_R: u32 = 0x00000004; + pub const PF_PAGEEXEC: u32 = 0x00000010; // from: uclibc-ng + pub const PF_NOPAGEEXEC: u32 = 0x00000020; // from: uclibc-ng + pub const PF_SEGMEXEC: u32 = 0x00000040; // from: uclibc-ng + pub const PF_NOSEGMEXEC: u32 = 0x00000080; // from: uclibc-ng + pub const PF_MPROTECT: u32 = 0x00000100; // from: uclibc-ng + pub const PF_NOMPROTECT: u32 = 0x00000200; // from: uclibc-ng + pub const PF_RANDEXEC: u32 = 0x00000400; // from: uclibc-ng + pub const PF_NORANDEXEC: u32 = 0x00000800; // from: uclibc-ng + pub const PF_EMUTRAMP: u32 = 0x00001000; // from: uclibc-ng + pub const PF_NOEMUTRAMP: u32 = 0x00002000; // from: uclibc-ng + pub const PF_RANDMMAP: u32 = 0x00004000; // from: uclibc-ng + pub const PF_NORANDMMAP: u32 = 0x00008000; // from: uclibc-ng + pub const PF_MASKOS: u32 = 0x0ff00000; + pub const PF_MASKPROC: u32 = 0xf0000000; + + pub const STB_LOCAL: u8 = 0; + pub const STB_GLOBAL: u8 = 1; + pub const STB_WEAK: u8 = 2; + pub const STB_LOOS: u8 = 10; + pub const STB_GNU_UNIQUE: u8 = 10; + pub const STB_HIOS: u8 = 12; + pub const STB_LOPROC: u8 = 13; + pub const STB_MIPS_SPLIT_COMMON: u8 = 13; + pub const STB_HIPROC: u8 = 15; + + pub const STT_NOTYPE: u8 = 0; + pub const STT_OBJECT: u8 = 1; + pub const STT_FUNC: u8 = 2; + pub const STT_SECTION: u8 = 3; + pub const STT_FILE: u8 = 4; + pub const STT_COMMON: u8 = 5; + pub const STT_TLS: u8 = 6; + pub const STT_LOOS: u8 = 10; + pub const STT_GNU_IFUNC: u8 = 10; + pub const STT_HP_OPAQUE: u8 = 11; + pub const STT_HP_STUB: u8 = 12; + pub const STT_HIOS: u8 = 12; + pub const STT_LOPROC: u8 = 13; + pub const STT_ARM_TFUNC: u8 = 13; + pub const STT_PARISC_MILLICODE: u8 = 13; + pub const STT_SPARC_REGISTER: u8 = 13; + pub const STT_ARM_16BIT: u8 = 15; + pub const STT_HIPROC: u8 = 15; + + pub const STV_DEFAULT: u8 = 0; + pub const STV_INTERNAL: u8 = 1; + pub const STV_HIDDEN: u8 = 2; + pub const STV_PROTECTED: u8 = 3; + pub const STV_EXPORTED: u8 = 4; // from: bionic + pub const STV_SINGLETON: u8 = 5; // from: bionic + pub const STV_ELIMINATE: u8 = 6; // from: bionic + + pub const DT_NULL: u32 = 0; + pub const DT_NEEDED: u32 = 1; + pub const DT_PLTRELSZ: u32 = 2; + pub const DT_PLTGOT: u32 = 3; + pub const DT_HASH: u32 = 4; + pub const DT_STRTAB: u32 = 5; + pub const DT_SYMTAB: u32 = 6; + pub const DT_RELA: u32 = 7; + pub const DT_RELASZ: u32 = 8; + pub const DT_RELAENT: u32 = 9; + pub const DT_STRSZ: u32 = 10; + pub const DT_SYMENT: u32 = 11; + pub const DT_INIT: u32 = 12; + pub const DT_FINI: u32 = 13; + pub const DT_SONAME: u32 = 14; + pub const DT_RPATH: u32 = 15; + pub const DT_SYMBOLIC: u32 = 16; + pub const DT_REL: u32 = 17; + pub const DT_RELSZ: u32 = 18; + pub const DT_RELENT: u32 = 19; + pub const DT_PLTREL: u32 = 20; + pub const DT_DEBUG: u32 = 21; + pub const DT_TEXTREL: u32 = 22; + pub const DT_JMPREL: u32 = 23; + pub const DT_BIND_NOW: u32 = 24; + pub const DT_INIT_ARRAY: u32 = 25; + pub const DT_FINI_ARRAY: u32 = 26; + pub const DT_INIT_ARRAYSZ: u32 = 27; + pub const DT_FINI_ARRAYSZ: u32 = 28; + pub const DT_RUNPATH: u32 = 29; + pub const DT_FLAGS: u32 = 30; + pub const DT_ENCODING: u32 = 32; + pub const DT_PREINIT_ARRAY: u32 = 32; + pub const DT_PREINIT_ARRAYSZ: u32 = 33; + pub const DT_SYMTAB_SHNDX: u32 = 34; + pub const DT_RELRSZ: u32 = 35; + pub const DT_RELR: u32 = 36; + pub const DT_RELRENT: u32 = 37; + pub const DT_LOOS: u32 = 0x6000000d; + pub const DT_HIOS: u32 = 0x6ffff000; + pub const DT_LOPROC: u32 = 0x70000000; + pub const DT_HIPROC: u32 = 0x7fffffff; + + pub const DT_SUNW_AUXILIARY: u32 = 0x6000000d; + pub const DT_SUNW_RTLDINF: u32 = 0x6000000e; + pub const DT_SUNW_FILTER: u32 = 0x6000000f; + pub const DT_SUNW_CAP: u32 = 0x60000010; + pub const DT_SUNW_ASLR: u32 = 0x60000023; + + pub const DT_VALRNGLO: u32 = 0x6ffffd00; + pub const DT_GNU_PRELINKED: u32 = 0x6ffffdf5; + pub const DT_GNU_CONFLICTSZ: u32 = 0x6ffffdf6; + pub const DT_GNU_LIBLISTSZ: u32 = 0x6ffffdf7; + pub const DT_CHECKSUM: u32 = 0x6ffffdf8; + pub const DT_PLTPADSZ: u32 = 0x6ffffdf9; + pub const DT_MOVEENT: u32 = 0x6ffffdfa; + pub const DT_MOVESZ: u32 = 0x6ffffdfb; + pub const DT_FEATURE_1: u32 = 0x6ffffdfc; + pub const DT_POSFLAG_1: u32 = 0x6ffffdfd; + pub const DT_SYMINSZ: u32 = 0x6ffffdfe; + pub const DT_SYMINENT: u32 = 0x6ffffdff; + pub const DT_VALRNGHI: u32 = 0x6ffffdff; + + pub const DT_ADDRRNGLO: u32 = 0x6ffffe00; + pub const DT_GNU_HASH: u32 = 0x6ffffef5; + pub const DT_TLSDESC_PLT: u32 = 0x6ffffef6; + pub const DT_TLSDESC_GOT: u32 = 0x6ffffef7; + pub const DT_GNU_CONFLICT: u32 = 0x6ffffef8; + pub const DT_GNU_LIBLIST: u32 = 0x6ffffef9; + pub const DT_CONFIG: u32 = 0x6ffffefa; + pub const DT_DEPAUDIT: u32 = 0x6ffffefb; + pub const DT_AUDIT: u32 = 0x6ffffefc; + pub const DT_PLTPAD: u32 = 0x6ffffefd; + pub const DT_MOVETAB: u32 = 0x6ffffefe; + pub const DT_SYMINFO: u32 = 0x6ffffeff; + pub const DT_ADDRRNGHI: u32 = 0x6ffffeff; + + pub const DT_VERSYM: u32 = 0x6ffffff0; + pub const DT_RELACOUNT: u32 = 0x6ffffff9; + pub const DT_RELCOUNT: u32 = 0x6ffffffa; + pub const DT_FLAGS_1: u32 = 0x6ffffffb; + pub const DT_VERDEF: u32 = 0x6ffffffc; + pub const DT_VERDEFNUM: u32 = 0x6ffffffd; + pub const DT_VERNEED: u32 = 0x6ffffffe; + pub const DT_VERNEEDNUM: u32 = 0x6fffffff; + + pub const DT_AUXILIARY: u32 = 0x7ffffffd; + pub const DT_USED: u32 = 0x7ffffffe; + pub const DT_FILTER: u32 = 0x7fffffff; + + pub const DF_ORIGIN: u32 = 0x00000001; + pub const DF_SYMBOLIC: u32 = 0x00000002; + pub const DF_TEXTREL: u32 = 0x00000004; + pub const DF_BIND_NOW: u32 = 0x00000008; + pub const DF_STATIC_TLS: u32 = 0x00000010; + + pub const DF_1_NOW: u32 = 0x00000001; + pub const DF_1_GLOBAL: u32 = 0x00000002; + pub const DF_1_GROUP: u32 = 0x00000004; + pub const DF_1_NODELETE: u32 = 0x00000008; + pub const DF_1_LOADFLTR: u32 = 0x00000010; + pub const DF_1_INITFIRST: u32 = 0x00000020; + pub const DF_1_NOOPEN: u32 = 0x00000040; + pub const DF_1_ORIGIN: u32 = 0x00000080; + pub const DF_1_DIRECT: u32 = 0x00000100; + pub const DF_1_TRANS: u32 = 0x00000200; + pub const DF_1_INTERPOSE: u32 = 0x00000400; + pub const DF_1_NODEFLIB: u32 = 0x00000800; + pub const DF_1_NODUMP: u32 = 0x00001000; + pub const DF_1_CONFALT: u32 = 0x00002000; + pub const DF_1_ENDFILTEE: u32 = 0x00004000; + pub const DF_1_DISPRELDNE: u32 = 0x00008000; + pub const DF_1_DISPRELPND: u32 = 0x00010000; + pub const DF_1_NODIRECT: u32 = 0x00020000; + pub const DF_1_IGNMULDEF: u32 = 0x00040000; + pub const DF_1_NOKSYMS: u32 = 0x00080000; + pub const DF_1_NOHDR: u32 = 0x00100000; + pub const DF_1_EDITED: u32 = 0x00200000; + pub const DF_1_NORELOC: u32 = 0x00400000; + pub const DF_1_SYMINTPOSE: u32 = 0x00800000; + pub const DF_1_GLOBAUDIT: u32 = 0x01000000; + pub const DF_1_SINGLETON: u32 = 0x02000000; + pub const DF_1_STUB: u32 = 0x04000000; + pub const DF_1_PIE: u32 = 0x08000000; + pub const DF_1_KMOD: u32 = 0x10000000; + pub const DF_1_WEAKFILTER: u32 = 0x20000000; + pub const DF_1_NOCOMMON: u32 = 0x40000000; + + pub const DTF_1_PARINIT: u32 = 0x00000001; + pub const DTF_1_CONFEXP: u32 = 0x00000002; + + pub const DF_P1_LAZYLOAD: u32 = 0x00000001; + pub const DF_P1_GROUPPERM: u32 = 0x00000002; + + /// Identification Table + /// + /// The first 16 bytes of the ELF header contain the identification table. + /// Typically, it is represented as a 16-byte array with open-coded byte + /// offsets. For better readability, this implementation provides a 1-byte + /// aligned structure with named member fields. + #[derive(Clone, Copy, Debug)] + #[repr(C)] + pub struct Ident { + pub i_magic: [u8; 4], + pub i_class: u8, + pub i_data: u8, + pub i_version: u8, + pub i_osabi: u8, + pub i_abiversion: u8, + pub i_pad: [u8; 7], + } +} + +macro_rules! impl_elf { + ( + $mod:ident, + $align:meta, + $usize:ty, + $isize:ty, + ($($ty_phdr:tt)*), + ($($ty_sym:tt)*) + $(,)? + ) => { + /// ELF Header + /// + /// The first bytes of an ELF file are occupied by the ELF header, + /// which itself starts with the ELF identification table. + #[derive(Clone, Copy, Debug)] + #[repr(C, $align)] + pub struct Ehdr { + pub e_ident: Ident, + pub e_type: u16, + pub e_machine: u16, + pub e_version: u32, + pub e_entry: $usize, + pub e_phoff: $usize, + pub e_shoff: $usize, + pub e_flags: u32, + pub e_ehsize: u16, + pub e_phentsize: u16, + pub e_phnum: u16, + pub e_shentsize: u16, + pub e_shnum: u16, + pub e_shstrndx: u16, + } + + /// Section Header + /// + /// A section header describes a section of an ELF file. It contains + /// all metadata on the section and points to the relevant parts in the + /// file for section content. + #[derive(Clone, Copy, Debug)] + #[repr(C, $align)] + pub struct Shdr { + pub sh_name: u32, + pub sh_type: u32, + pub sh_flags: $usize, + pub sh_addr: $usize, + pub sh_offset: $usize, + pub sh_size: $usize, + pub sh_link: u32, + pub sh_info: u32, + pub sh_addralign: $usize, + pub sh_entsize: $usize, + } + + /// Program Header + /// + /// A program header describes a segment of an ELF file. It contains + /// all metadata relevant to a segment and points to the segment data + /// in the file. + $($ty_phdr)* + + /// Symbol Value + /// + /// A symbol is a named reference to data in an ELF file. The symbol + /// header describes the metadata relevant to a symbol. + $($ty_sym)* + + /// Dynamic Sections + /// + /// The dynamic section contains information needed for dynamic loading + /// and linking of the binary. It is usually exported in the dynamic + /// segment. + /// + /// # Inlined Value + /// + /// Traditionally, the struct has a `d_un` field, which itself is a + /// union with two equally sized fields `d_val` and `d_ptr`. Since they + /// have the same size and evaluate to the same integer type, they are + /// merely documentational. + /// + /// This Rust struct uses `d_val` directly and does not provide any + /// alias. This makes the struct a lot easier to work with in Rust, + /// since a union would require a lot of manual trait implementations + /// and unsafe operations, which seems excessive given that it is a + /// mere alias. + #[derive(Clone, Copy, Debug)] + #[repr(C, $align)] + pub struct Dyn { + pub d_tag: $usize, + pub d_val: $usize, + } + + /// Relocation Information + /// + /// Code relocations with implicit addend use this structure to + /// describe all relevant metadata for the relocation. + #[derive(Clone, Copy, Debug)] + #[repr(C, $align)] + pub struct Rel { + pub r_offset: $usize, + pub r_info: $usize, + } + + /// Relocation Information with Addend + /// + /// Code relocations with explicit addend use this structure to + /// describe all relevant metadata for the relocation. + #[derive(Clone, Copy, Debug)] + #[repr(C, $align)] + pub struct Rela { + pub r_offset: $usize, + pub r_info: $usize, + pub r_addend: $isize, + } + }; +} + +/// # ELF for 32-bit +/// +/// This module exposes the ELF API for 32-bit machines. +pub mod elf32 { + pub use super::common::*; + + impl_elf!( + elf32, + align(4), + u32, + i32, + ( + #[derive(Clone, Copy, Debug)] + #[repr(C, align(4))] + pub struct Phdr { + pub p_type: u32, + pub p_offset: u32, + pub p_vaddr: u32, + pub p_paddr: u32, + pub p_filesz: u32, + pub p_memsz: u32, + pub p_flags: u32, + pub p_align: u32, + } + ), + ( + #[derive(Clone, Copy, Debug)] + #[repr(C, align(4))] + pub struct Sym { + pub st_name: u32, + pub st_value: u32, + pub st_size: u32, + pub st_info: u8, + pub st_other: u8, + pub st_shndx: u16, + } + ), + ); +} + +/// # ELF for 64-bit +/// +/// This module exposes the ELF API for 64-bit machines. +pub mod elf64 { + pub use super::common::*; + + impl_elf!( + elf64, + align(8), + u64, + i64, + ( + #[derive(Clone, Copy, Debug)] + #[repr(C, align(8))] + pub struct Phdr { + pub p_type: u32, + pub p_flags: u32, + pub p_offset: u64, + pub p_vaddr: u64, + pub p_paddr: u64, + pub p_filesz: u64, + pub p_memsz: u64, + pub p_align: u64, + } + ), + ( + #[derive(Clone, Copy, Debug)] + #[repr(C, align(8))] + pub struct Sym { + pub st_name: u32, + pub st_info: u8, + pub st_other: u8, + pub st_shndx: u16, + pub st_value: u64, + pub st_size: u64, + } + ), + ); +} + +/// # ELF for Native Access +/// +/// This module is an alias for either [`elf32`] or [`elf64`], matching the +/// format used by the target platform. +#[cfg(target_pointer_width = "32")] +pub use elf32 as elfn; +#[cfg(target_pointer_width = "64")] +pub use elf64 as elfn; + +#[cfg(test)] +mod test { + use super::*; + + // Verify that `elfn` represents the native platform. + #[test] + fn native() { + // `Rel` contains two addresses, so it must be aligned respectively. + assert_eq!(align_of::(), align_of::()); + assert_eq!(size_of::(), size_of::() * 2); + + // Similarly, ensure that `Rel` matches the target pointer width. We + // use this to figure out the native ELF style. + osi::cfg::cond! { + (target_pointer_width = "32") { + assert_eq!(align_of::(), 4); + assert_eq!(size_of::(), 8); + }, + (target_pointer_width = "64") { + assert_eq!(align_of::(), 8); + assert_eq!(size_of::(), 16); + }, + } + } + + // Verify that the different ELF structures are aligned and sized as + // expected. + #[test] + fn typeinfo() { + assert_eq!(align_of::(), 1); + assert_eq!(size_of::(), 16); + + assert_eq!(align_of::(), 1); + assert_eq!(size_of::(), 16); + assert_eq!(align_of::(), 4); + assert_eq!(size_of::(), 52); + assert_eq!(align_of::(), 4); + assert_eq!(size_of::(), 40); + assert_eq!(align_of::(), 4); + assert_eq!(size_of::(), 32); + assert_eq!(align_of::(), 4); + assert_eq!(size_of::(), 16); + assert_eq!(align_of::(), 4); + assert_eq!(size_of::(), 8); + assert_eq!(align_of::(), 4); + assert_eq!(size_of::(), 8); + assert_eq!(align_of::(), 4); + assert_eq!(size_of::(), 12); + + assert_eq!(align_of::(), 1); + assert_eq!(size_of::(), 16); + assert_eq!(align_of::(), 8); + assert_eq!(size_of::(), 64); + assert_eq!(align_of::(), 8); + assert_eq!(size_of::(), 64); + assert_eq!(align_of::(), 8); + assert_eq!(size_of::(), 56); + assert_eq!(align_of::(), 8); + assert_eq!(size_of::(), 24); + assert_eq!(align_of::(), 8); + assert_eq!(size_of::(), 16); + assert_eq!(align_of::(), 8); + assert_eq!(size_of::(), 16); + assert_eq!(align_of::(), 8); + assert_eq!(size_of::(), 24); + } + + // Compare the ELF structures to their libc counterparts. + #[cfg(feature = "libc")] + #[test] + fn compare_libc() { + assert_eq!(size_of::(), size_of::()); + assert_eq!(size_of::(), size_of::()); + assert_eq!(size_of::(), size_of::()); + assert_eq!(size_of::(), size_of::()); + assert_eq!(size_of::(), 8); + assert_eq!(size_of::(), size_of::()); + assert_eq!(size_of::(), size_of::()); + + assert_eq!(size_of::(), size_of::()); + assert_eq!(size_of::(), size_of::()); + assert_eq!(size_of::(), size_of::()); + assert_eq!(size_of::(), size_of::()); + assert_eq!(size_of::(), 16); + assert_eq!(size_of::(), size_of::()); + assert_eq!(size_of::(), size_of::()); + + assert_eq!(align_of::(), align_of::()); + assert_eq!(align_of::(), align_of::()); + assert_eq!(align_of::(), align_of::()); + assert_eq!(align_of::(), align_of::()); + assert_eq!(align_of::(), 4); + assert_eq!(align_of::(), align_of::()); + assert_eq!(align_of::(), align_of::()); + + assert_eq!(align_of::(), align_of::()); + assert_eq!(align_of::(), align_of::()); + assert_eq!(align_of::(), align_of::()); + assert_eq!(align_of::(), align_of::()); + assert_eq!(align_of::(), 8); + assert_eq!(align_of::(), align_of::()); + assert_eq!(align_of::(), align_of::()); + } +} diff --git a/lib/sys/src/ffi/mod.rs b/lib/sys/src/ffi/mod.rs index ddfedb1..5e2eb96 100644 --- a/lib/sys/src/ffi/mod.rs +++ b/lib/sys/src/ffi/mod.rs @@ -70,4 +70,5 @@ //! as suffix instead (e.g., `elf32`, `elf64`, `elfn`, where the latter is the //! equivalent of _"native"_). +pub mod elf; pub mod linux; From 39ced5748b44bb6803bd5074272b6ec3b36f0e90 Mon Sep 17 00:00:00 2001 From: David Rheinsberg Date: Tue, 28 Apr 2026 09:45:48 +0200 Subject: [PATCH 09/10] sys/ffi/elf: catch misaligned foreign types in libc Avoid comparing alignments of foreign types against libc. The types in `libc` are not correctly aligned, unless they a native to the target platform. Hence, only compare alignment for native types. Signed-off-by: David Rheinsberg --- lib/sys/src/ffi/elf.rs | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/lib/sys/src/ffi/elf.rs b/lib/sys/src/ffi/elf.rs index df7364c..efd7d17 100644 --- a/lib/sys/src/ffi/elf.rs +++ b/lib/sys/src/ffi/elf.rs @@ -959,20 +959,27 @@ mod test { assert_eq!(size_of::(), size_of::()); assert_eq!(size_of::(), size_of::()); - assert_eq!(align_of::(), align_of::()); - assert_eq!(align_of::(), align_of::()); - assert_eq!(align_of::(), align_of::()); - assert_eq!(align_of::(), align_of::()); - assert_eq!(align_of::(), 4); - assert_eq!(align_of::(), align_of::()); - assert_eq!(align_of::(), align_of::()); - - assert_eq!(align_of::(), align_of::()); - assert_eq!(align_of::(), align_of::()); - assert_eq!(align_of::(), align_of::()); - assert_eq!(align_of::(), align_of::()); - assert_eq!(align_of::(), 8); - assert_eq!(align_of::(), align_of::()); - assert_eq!(align_of::(), align_of::()); + // `libc` does not align foreign types correctly. Run the test only on + // a native platform. + osi::cfg::cond! { + (target_pointer_width = "32") { + assert_eq!(align_of::(), align_of::()); + assert_eq!(align_of::(), align_of::()); + assert_eq!(align_of::(), align_of::()); + assert_eq!(align_of::(), align_of::()); + assert_eq!(align_of::(), 4); + assert_eq!(align_of::(), align_of::()); + assert_eq!(align_of::(), align_of::()); + }, + (target_pointer_width = "64") { + assert_eq!(align_of::(), align_of::()); + assert_eq!(align_of::(), align_of::()); + assert_eq!(align_of::(), align_of::()); + assert_eq!(align_of::(), align_of::()); + assert_eq!(align_of::(), 8); + assert_eq!(align_of::(), align_of::()); + assert_eq!(align_of::(), align_of::()); + }, + } } } From a6b6d45562d60687358fe594a88de5fdf276fb34 Mon Sep 17 00:00:00 2001 From: David Rheinsberg Date: Tue, 28 Apr 2026 10:26:28 +0200 Subject: [PATCH 10/10] osi/ffi/abi: fix x86 alignment of 128-bit integers Fix the alignment of i128 and u128 to 16 for i686. This was already fixed for x86-64, but not for x86 proper. This changed semi-recently in rustc and now matches the respective ABI. Unfortunately, x86 does not define 128-bit integers in its ABI and likely never will. But all compilers now agree to use 16-byte alignment for them, given that 128-bit floating points do so on x86. Signed-off-by: David Rheinsberg --- lib/osi/src/ffi/abi.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/osi/src/ffi/abi.rs b/lib/osi/src/ffi/abi.rs index 302508e..ce84bb7 100644 --- a/lib/osi/src/ffi/abi.rs +++ b/lib/osi/src/ffi/abi.rs @@ -138,14 +138,14 @@ pub mod x86_sysv { pub type I16 = super::Le>; pub type I32 = super::Le>; pub type I64 = super::Le>; - pub type I128 = super::Le>; + pub type I128 = super::Le>; pub type Isize = super::Le>; pub type U8 = super::Le>; pub type U16 = super::Le>; pub type U32 = super::Le>; pub type U64 = super::Le>; - pub type U128 = super::Le>; + pub type U128 = super::Le>; pub type Usize = super::Le>; pub type F32 = super::Le>;