Skip to main content

osi/ffi/
abi.rs

1//! Common ABIs
2//!
3//! This module provides type definitions for a set of platform ABIs. This can
4//! be used to introspect or synthesize objects of foreign platform ABIs.
5//!
6//! The individual sub-modules represent known ABIs of different platforms.
7//! Each module exports the same set of symbols. Preferably, this would be
8//! represented by a trait, which is implemented by each ABI. Unfortunately,
9//! Rust traits are too limited right now to be suitable here (most
10//! importantly, they do not allow constant methods). Hence, we instead export
11//! a set of modules.
12//!
13//! [`native`] exports a special ABI which always represents the ABI of the
14//! target platform and uses the Rust native data-types (i.e., it uses the
15//! builtin primitive integers like `u16`, `i64`, and `usize`). Use this ABI
16//! to get a native Rust experience. This is suitable if foreign data access
17//! is not needed.
18//!
19//! [`auto`] is an alias of one of the other ABIs and represents the target
20//! platform. Unlike [`native`], this does not necessarily use native Rust
21//! data-types, but is a real alias to one of the other fixed definitions of
22//! platform ABIs.
23//!
24//! ## Foreign ABI
25//!
26//! When accessing foreign ABIs, care must be taken to ensure datatypes have
27//! the correct layout. The builtin primitives like `u32`, `i64`, etc., always
28//! follow the native ABI, and thus cannot be reliably used to represent
29//! data-structures of foreign ABIs. The utilities in this module can be used
30//! instead.
31//!
32//! As an example, imagine a 32-bit Linux process that visualizes core-dumps of
33//! crashed processes. If that process needs to read core-dumps of a 64-bit
34//! system, it likely cannot use `u64` to model the structures used in that
35//! core-dump, since it will have an alignment of 4, rather than the original
36//! alignment of 8. Instead, [`crate::ffi::Integer`] can be used to model the
37//! exact ABI of the foreign system.
38
39// Little-endian integer with the given native type and alignment.
40type Le<Native, Alignment> = crate::ffi::Integer<
41    crate::ffi::LittleEndian<Native>,
42    Alignment,
43>;
44
45// This module is imported by all ABIs and provides default symbols valid on
46// all targets.
47mod shared {
48    /// Creates a number by converting the input value from native
49    /// representation into the representation of the target type.
50    ///
51    /// This is the preferred method to initialize foreign ordered datatypes
52    /// with a logical value. This method will take care of endian conversion,
53    /// such that a machine of the foreign platform would read the same logical
54    /// value.
55    ///
56    /// If this method is used to initialize non-foreign (native) datatypes,
57    /// it will be an identity function and return the input unchanged.
58    ///
59    /// This works with any type that implements [`crate::ffi::NativeEndian`].
60    pub const fn num<Endian: crate::ffi::NativeEndian<Raw>, Raw: Copy>(r: Raw) -> Endian {
61        crate::ffi::from_native(r)
62    }
63}
64
65/// # Native ABI
66///
67/// The native ABI uses the native primitive types of Rust, and thus represents
68/// the ABI of the compilation target platform. This is the preferred ABI to
69/// use when interfacing with native platform APIs, rather than foreign
70/// platform APIs.
71///
72/// The types of this ABI directly alias Rust primitive types like `u16` or
73/// `i64`. Hence, these should integrate nicely into native Rust code bases and
74/// no special handling is needed.
75pub mod native {
76    pub type I8 = i8;
77    pub type I16 = i16;
78    pub type I32 = i32;
79    pub type I64 = i64;
80    pub type I128 = i128;
81    pub type Isize = isize;
82
83    pub type U8 = u8;
84    pub type U16 = u16;
85    pub type U32 = u32;
86    pub type U64 = u64;
87    pub type U128 = u128;
88    pub type Usize = usize;
89
90    pub type F32 = f32;
91    pub type F64 = f64;
92
93    pub type Addr = core::num::NonZeroUsize;
94    pub type Ptr<Target> = core::ptr::NonNull<Target>;
95
96    pub use super::shared::*;
97}
98
99/// # System-V x86 ABI
100///
101/// This ABI represents the 32-bit ABI of System-V for x86 systems. It is used
102/// by most UNIX compatible systems, including Linux.
103pub mod x86_sysv {
104    use crate::align;
105
106    pub type I8 = super::Le<i8, align::AlignAs<1>>;
107    pub type I16 = super::Le<i16, align::AlignAs<2>>;
108    pub type I32 = super::Le<i32, align::AlignAs<4>>;
109    pub type I64 = super::Le<i64, align::AlignAs<4>>;
110    pub type I128 = super::Le<i128, align::AlignAs<4>>;
111    pub type Isize = super::Le<i32, align::AlignAs<4>>;
112
113    pub type U8 = super::Le<u8, align::AlignAs<1>>;
114    pub type U16 = super::Le<u16, align::AlignAs<2>>;
115    pub type U32 = super::Le<u32, align::AlignAs<4>>;
116    pub type U64 = super::Le<u64, align::AlignAs<4>>;
117    pub type U128 = super::Le<u128, align::AlignAs<4>>;
118    pub type Usize = super::Le<u32, align::AlignAs<4>>;
119
120    pub type F32 = super::Le<f32, align::AlignAs<4>>;
121    pub type F64 = super::Le<f64, align::AlignAs<4>>;
122
123    pub type Addr = super::Le<core::num::NonZeroU32, align::AlignAs<4>>;
124    pub type Ptr<Target> = crate::ffi::Pointer<Addr, Target>;
125
126    pub use super::shared::*;
127}
128
129/// # System-V x86-64 ABI
130///
131/// This ABI represents the 64-bit ABI of System-V for x86 systems. It is used
132/// by most UNIX compatible systems, including Linux.
133pub mod x86_64_sysv {
134    use crate::align;
135
136    pub type I8 = super::Le<i8, align::AlignAs<1>>;
137    pub type I16 = super::Le<i16, align::AlignAs<2>>;
138    pub type I32 = super::Le<i32, align::AlignAs<4>>;
139    pub type I64 = super::Le<i64, align::AlignAs<8>>;
140    pub type I128 = super::Le<i128, align::AlignAs<16>>;
141    pub type Isize = super::Le<i64, align::AlignAs<8>>;
142
143    pub type U8 = super::Le<u8, align::AlignAs<1>>;
144    pub type U16 = super::Le<u16, align::AlignAs<2>>;
145    pub type U32 = super::Le<u32, align::AlignAs<4>>;
146    pub type U64 = super::Le<u64, align::AlignAs<8>>;
147    pub type U128 = super::Le<u128, align::AlignAs<16>>;
148    pub type Usize = super::Le<u64, align::AlignAs<8>>;
149
150    pub type F32 = super::Le<f32, align::AlignAs<4>>;
151    pub type F64 = super::Le<f64, align::AlignAs<8>>;
152
153    pub type Addr = super::Le<core::num::NonZeroU64, align::AlignAs<8>>;
154    pub type Ptr<Target> = crate::ffi::Pointer<Addr, Target>;
155
156    pub use super::shared::*;
157}
158
159#[cfg(all(
160    target_arch = "x86",
161    target_family = "unix",
162))]
163pub use x86_sysv as auto;
164
165#[cfg(all(
166    target_arch = "x86_64",
167    target_family = "unix",
168))]
169pub use x86_64_sysv as auto;
170
171#[cfg(all(
172    target_arch = "x86",
173    target_env = "msvc",
174    target_family = "windows",
175))]
176pub use x86_win as auto;
177
178#[cfg(all(
179    target_arch = "x86_64",
180    target_env = "msvc",
181    target_family = "windows",
182))]
183pub use x86_64_win as auto;