Skip to main content

link_section/
lib.rs

1#![doc = include_str!("../README.md")]
2#![allow(unsafe_code)]
3
4#[doc(hidden)]
5pub mod __support {
6    pub use crate::__in_section_crate as in_section_crate;
7    pub use crate::__in_section_parse as in_section_parse;
8    pub use crate::__section_name as section_name;
9    pub use crate::__section_parse as section_parse;
10
11    pub use link_section_proc_macro::hash;
12
13    #[cfg(target_vendor = "apple")]
14    #[macro_export]
15    #[doc(hidden)]
16    macro_rules! __section_name {
17        ($pattern:tt data $($rest:tt)*) => {
18            $crate::__support::section_name!(__ $pattern symbol "__DATA" $($rest)*);
19        };
20        ($pattern:tt code $($rest:tt)*) => {
21            $crate::__support::section_name!(__ $pattern symbol "__TEXT" $($rest)*);
22        };
23        ($pattern:tt $unknown_section:ident $($rest:tt)*) => {
24            const _: () = {
25                compile_error!("Unknown section type: `{}`", stringify!($unknown_section));
26            };
27        };
28
29        (__ $pattern:tt symbol $section_prefix:literal bare $name:ident) => {
30            $crate::__support::section_name!(__ $pattern hash ($section_prefix ",") () $name);
31        };
32        (__ $pattern:tt symbol $section_prefix:literal section $name:ident) => {
33            $crate::__support::section_name!(__ $pattern hash ($section_prefix ",") (",regular,no_dead_strip") $name);
34        };
35        (__ $pattern:tt symbol $section_prefix:literal start $name:ident) => {
36            // \x01: "do not mangle" (ref https://github.com/rust-lang/rust-bindgen/issues/2935)
37            $crate::__support::section_name!(__ $pattern hash ("\x01section$start$" $section_prefix "$") () $name);
38        };
39        (__ $pattern:tt symbol $section_prefix:literal end $name:ident) => {
40            $crate::__support::section_name!(__ $pattern hash ("\x01section$end$" $section_prefix "$") ()$name);
41        };
42
43        (__ $pattern:tt hash $prefix:tt $suffix:tt $name:ident) => {
44            $crate::__support::hash!($pattern $name $prefix $suffix 6 16 "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
45        };
46    }
47
48    #[cfg(all(not(target_vendor = "apple"), not(target_vendor = "pc")))]
49    #[macro_export]
50    #[doc(hidden)]
51    macro_rules! __section_name {
52        ($pattern:tt data $($rest:tt)*) => {
53            $crate::__support::section_name!(__ $pattern symbol "_data" $($rest)*);
54        };
55        ($pattern:tt code $($rest:tt)*) => {
56            $crate::__support::section_name!(__ $pattern symbol "_text" $($rest)*);
57        };
58        ($pattern:tt $unknown_section:ident $($rest:tt)*) => {
59            const _: () = {
60                compile_error!("Unknown section type: `{}`", stringify!($unknown_section));
61            };
62        };
63
64        // Ideally we'd use .data and .text, but we cannot guarantee name
65        // sorting of sections in the linker script
66        (__ $pattern:tt symbol $section_prefix:literal bare $name:ident) => {
67            $crate::__support::section_name!(__ $pattern hash ($section_prefix "_link_section_") () $name);
68        };
69        (__ $pattern:tt symbol $section_prefix:literal section $name:ident) => {
70            $crate::__support::section_name!(__ $pattern hash ($section_prefix "_link_section_") () $name);
71        };
72        (__ $pattern:tt symbol $section_prefix:literal start $name:ident) => {
73            $crate::__support::section_name!(__ $pattern hash ("__start_" $section_prefix "_link_section_") () $name);
74        };
75        (__ $pattern:tt symbol $section_prefix:literal end $name:ident) => {
76            $crate::__support::section_name!(__ $pattern hash ("__stop_" $section_prefix "_link_section_") () $name);
77        };
78
79        (__ $pattern:tt hash $prefix:tt $suffix:tt $name:ident) => {
80            $crate::__support::hash!($pattern $name $prefix $suffix 10 64 "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
81        };
82    }
83
84    #[cfg(target_vendor = "pc")]
85    #[macro_export]
86    #[doc(hidden)]
87    macro_rules! __section_name {
88        ($pattern:tt data $($rest:tt)*) => {
89            $crate::__support::section_name!(__ $pattern symbol ".data" $($rest)*);
90        };
91        ($pattern:tt code $($rest:tt)*) => {
92            $crate::__support::section_name!(__ $pattern symbol ".text" $($rest)*);
93        };
94        ($pattern:tt $unknown_section:ident $($rest:tt)*) => {
95            const _: () = {
96                compile_error!("Unknown section type: `{}`", stringify!($unknown_section));
97            };
98        };
99
100        (__ $pattern:tt symbol $section_prefix:literal bare $name:ident) => {
101            $crate::__support::section_name!(__ $pattern hash ($section_prefix "$") () $name);
102        };
103        (__ $pattern:tt symbol $section_prefix:literal section $name:ident) => {
104            $crate::__support::section_name!(__ $pattern hash ($section_prefix "$") ("$b") $name);
105        };
106        (__ $pattern:tt symbol $section_prefix:literal start $name:ident) => {
107            $crate::__support::section_name!(__ $pattern hash ($section_prefix "$") ("$a") $name);
108        };
109        (__ $pattern:tt symbol $section_prefix:literal end $name:ident) => {
110            $crate::__support::section_name!(__ $pattern hash ($section_prefix "$") ("$c") $name);
111        };
112
113        (__ $pattern:tt hash $prefix:tt $suffix:tt $name:ident) => {
114            $crate::__support::hash!($pattern $name $prefix $suffix 10 64 "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
115        };
116    }
117
118    /// Define a link section.
119    #[macro_export]
120    #[doc(hidden)]
121    macro_rules! __section_parse {
122        // Has a generic (note that $generic eats the trailing semicolon)
123        (#[section] $(#[$meta:meta])* $vis:vis static $ident:ident : $(:: $path_prefix:ident ::)? $($path:ident)::* < $($generic:tt)*) => {
124            $crate::__section_parse!(#[section] $(#[$meta])* $vis static $ident: ( $(:: $path_prefix ::)? $($path)::* < $($generic)*) ( $($generic)* ) generic);
125        };
126        // No generic
127        (#[section] $(#[$meta:meta])* $vis:vis static $ident:ident : $(:: $path_prefix:ident ::)? $($path:ident)::* ;) => {
128            $crate::__section_parse!(#[section] $(#[$meta])* $vis static $ident: ( $(:: $path_prefix ::)? $($path)::* ;) ( () > ; ) no_generic);
129        };
130        // Both end up here...
131        (#[section] $(#[$meta:meta])* $vis:vis static $ident:ident : ($ty:ty ;) ( $generic_ty:ty > ; ) $generic:ident) => {
132            /// Internal macro for parsing the section.
133            macro_rules! $ident {
134                (v=0 (item=$item:tt $rest:tt)) => {
135                    $crate::__support::in_section_crate!($ident $generic $ty, $item);
136                };
137                (v=$v:literal $rest:tt) => {
138                    const _: () = { compile_error!(concat!("link-section: Unsupported version: `", stringify!($v), "`")); };
139                };
140            }
141
142            $(#[$meta])*
143            #[used]
144            $vis static $ident: $crate::__support::Section< $ty, $generic_ty > = $crate::__support::Section::new(
145                {
146                    $crate::__support::section_name!(
147                        (const fn section_name() -> &'static str { __ })
148                        data bare $ident
149                    );
150
151                    section_name()
152                },
153                {
154                    #[cfg(not(target_vendor = "pc"))]
155                    $crate::__support::section_name!(
156                        (
157                            extern "C" {
158                                #[link_name = __] static __START: $crate::__support::SectionPtr<$generic_ty>;
159                            }
160                        )
161                        data start $ident
162                    );
163
164                    // Windows always sorts, so we can use alphabetical order
165                    #[cfg(target_vendor = "pc")]
166                    $crate::__support::section_name!(
167                        (
168                            #[link_section = __]
169                            #[used]
170                            static __START: [$generic_ty; 0] = [];
171                        )
172                        data start $ident
173                    );
174
175                    unsafe { &raw const __START as $crate::__support::SectionPtr<$generic_ty> }
176                },
177                {
178                    #[cfg(not(target_vendor = "pc"))]
179                    $crate::__support::section_name!(
180                        (
181                            extern "C" {
182                                #[link_name = __] static __END: $crate::__support::SectionPtr<$generic_ty>;
183                            }
184                        )
185                        data end $ident
186                    );
187
188                    #[cfg(target_vendor = "pc")]
189                    $crate::__support::section_name!(
190                        (
191                            #[link_section = __]
192                            #[used]
193                            static __END: [$generic_ty; 0] = [];
194                        )
195                        data end $ident
196                    );
197
198                    unsafe { &raw const __END as $crate::__support::SectionPtr<$generic_ty> }
199                },
200            );
201        };
202    }
203
204    /// Export a symbol into a link section.
205    #[macro_export]
206    #[doc(hidden)]
207    macro_rules! __in_section_parse {
208        (#[in_section($name:path)] $($item:tt)*) => {
209            $name ! (
210                v=0 (item=($($item)*) ())
211            );
212        };
213    }
214
215    #[macro_export]
216    #[doc(hidden)]
217    #[allow(unknown_lints, edition_2024_expr_fragment_specifier)]
218    macro_rules! __in_section_crate {
219        ($ident:ident generic $section_ty:ty, ($(#[$meta:meta])* $vis:vis fn $ident_fn:ident($($args:tt)*) $(-> $ret:ty)? $body:block)) => {
220            $crate::__support::section_name!(
221                (
222                    // Split the function into a static item and a function pointer
223                    $(#[$meta])*
224                    #[used]
225                    #[link_section = __]
226                    #[allow(non_upper_case_globals)]
227                    $vis static $ident_fn: <$section_ty as $crate::__support::SectionItemType>::Item =
228                        {
229                            fn $ident_fn($($args)*) $(-> $ret)? $body
230                            $ident_fn as <$section_ty as $crate::__support::SectionItemType>::Item
231                        };
232                )
233                data section $ident
234            );
235        };
236        ($ident:ident generic $section_ty:ty, ($(#[$meta:meta])* $vis:vis static $ident_static:ident : $ty:ty = $value:expr;)) => {
237            $crate::__support::section_name!(
238                ($(#[$meta])* #[link_section = __] #[used] $vis static $ident_static: <$section_ty as $crate::__support::SectionItemType>::Item = $value;)
239                data section $ident
240            );
241        };
242        ($ident:ident no_generic $section_ty:ty, ($(#[$meta:meta])* $vis:vis fn $ident_fn:ident($($args:tt)*) $(-> $ret:ty)? $body:block)) => {
243            $crate::__support::section_name!(
244                (
245                    $(#[$meta])*
246                    #[link_section = __]
247                    #[used]
248                    #[allow(non_upper_case_globals)]
249                    $vis static $ident_fn: fn($($args)*) $(-> $ret)? =
250                        {
251                            $crate::__support::section_name!(
252                                (#[link_section = __] fn $ident_fn($($args)*) $(-> $ret)? $body)
253                                code section $ident
254                            );
255                            $ident_fn
256                        };
257                )
258                data section $ident
259            );
260        };
261        ($ident:ident no_generic $section_ty:ty, ($(#[$meta:meta])* $item:item)) => {
262            $crate::__support::section_name!(
263                ($(#[$meta])* #[link_section = __] #[used] $item)
264                data section $ident
265            );
266        };
267    }
268
269    pub trait SectionItemType {
270        type Item;
271    }
272
273    #[repr(C)]
274    pub struct Section<T: sealed::FromRawSection, S> {
275        name: &'static str,
276        start: SectionPtr<S>,
277        end: SectionPtr<S>,
278        _t: ::core::marker::PhantomData<T>,
279    }
280
281    impl<T> SectionItemType for super::TypedSection<T> {
282        type Item = T;
283    }
284
285    impl<T: sealed::FromRawSection, S> Section<T, S> {
286        pub const fn new(name: &'static str, start: SectionPtr<S>, end: SectionPtr<S>) -> Self {
287            Self {
288                name,
289                start,
290                end,
291                _t: ::core::marker::PhantomData,
292            }
293        }
294    }
295
296    impl<'a, T: sealed::FromRawSection, S> ::core::iter::IntoIterator for &'a Section<T, S>
297    where
298        for<'b> &'b T: ::core::iter::IntoIterator,
299    {
300        type Item = <&'a T as ::core::iter::IntoIterator>::Item;
301        type IntoIter = <&'a T as ::core::iter::IntoIterator>::IntoIter;
302        fn into_iter(self) -> Self::IntoIter {
303            ::core::ops::Deref::deref(self).into_iter()
304        }
305    }
306
307    impl<T: sealed::FromRawSection, S> ::core::ops::Deref for Section<T, S> {
308        type Target = T;
309        fn deref(&self) -> &Self::Target {
310            // SAFETY: all sections are repr(C)
311            unsafe { ::core::mem::transmute(self) }
312        }
313    }
314
315    impl<T: sealed::FromRawSection + ::core::fmt::Debug, S> ::core::fmt::Debug for Section<T, S> {
316        fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
317            ::core::fmt::Debug::fmt(::core::ops::Deref::deref(self), f)
318        }
319    }
320
321    unsafe impl<T: sealed::FromRawSection, S> Sync for Section<T, S> {}
322    unsafe impl<T: sealed::FromRawSection, S> Send for Section<T, S> {}
323
324    /// On Apple platforms, the linker provides a pointer to the start and end
325    /// of the section regardless of the section's name.
326    #[cfg(not(target_vendor = "pc"))]
327    pub type SectionPtr<T> = *const ::core::marker::PhantomData<T>;
328    /// On LLVM/GCC/MSVC platforms, we cannot use start/end symbols for sections
329    /// without C-compatible names, so instead we drop a [T; 0] at the start and
330    /// end of the section.
331    #[cfg(target_vendor = "pc")]
332    pub type SectionPtr<T> = *const [T; 0];
333
334    mod sealed {
335        pub trait FromRawSection {}
336
337        impl FromRawSection for crate::Section {}
338
339        impl<T> FromRawSection for crate::TypedSection<T> {}
340    }
341}
342
343/// Define a link section.
344///
345/// # Example
346/// ```rust
347/// use link_section::{in_section, section};
348///
349/// #[section]
350/// pub static DATA_SECTION: link_section::Section;
351///
352/// #[in_section(DATA_SECTION)]
353/// pub fn data_function() {
354///     println!("data_function");
355/// }
356/// ```
357pub use ::link_section_proc_macro::section;
358
359/// Place an item into a link section.
360///
361/// # Functions and typed sections
362///
363/// As a special case, since function declarations by themselves are not sized,
364/// functions in typed sections are split and stored as function pointers.
365pub use ::link_section_proc_macro::in_section;
366
367/// An untyped link section that can be used to store any type. The underlying
368/// data is not enumerable.
369#[repr(C)]
370pub struct Section {
371    name: &'static str,
372    start: __support::SectionPtr<()>,
373    end: __support::SectionPtr<()>,
374}
375
376impl Section {
377    /// The start address of the section.
378    pub const fn start_ptr(&self) -> *const () {
379        self.start as *const ()
380    }
381    /// The end address of the section.
382    pub const fn end_ptr(&self) -> *const () {
383        self.end as *const ()
384    }
385    /// The byte length of the section.
386    pub const fn byte_len(&self) -> usize {
387        unsafe { (self.end as *const u8).offset_from(self.start as *const u8) as usize }
388    }
389}
390
391impl ::core::fmt::Debug for Section {
392    fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
393        f.debug_struct("Section")
394            .field("name", &self.name)
395            .field("start", &self.start_ptr())
396            .field("end", &self.end_ptr())
397            .field("byte_len", &self.byte_len())
398            .finish()
399    }
400}
401
402unsafe impl Sync for Section {}
403unsafe impl Send for Section {}
404
405/// A typed link section that can be used to store any sized type. The
406/// underlying data is enumerable.
407#[repr(C)]
408pub struct TypedSection<T> {
409    name: &'static str,
410    start: __support::SectionPtr<T>,
411    end: __support::SectionPtr<T>,
412    _phantom: ::core::marker::PhantomData<T>,
413}
414
415impl<T> TypedSection<T> {
416    /// The stride of the typed section.
417    pub const fn stride(&self) -> usize {
418        // Compute the size required for C to store two instances of T side-by-side.
419        // TODO: Can we just use align_of/size_of?
420        #[repr(C)]
421        struct Sizer<T> {
422            t1: T,
423            t2: T,
424            t3: T,
425        }
426
427        let sizer = ::core::mem::MaybeUninit::<Sizer<T>>::uninit();
428        let ptr: *const Sizer<T> = sizer.as_ptr();
429        let start = ptr as *const u8;
430        let end = unsafe { ::core::ptr::addr_of!((*ptr).t3) } as *const u8;
431        unsafe { end.offset_from(start) as usize / 2 }
432    }
433
434    /// The start address of the section.
435    pub const fn start_ptr(&self) -> *const T {
436        self.start as *const T
437    }
438
439    /// The end address of the section.
440    pub const fn end_ptr(&self) -> *const T {
441        self.end as *const T
442    }
443
444    /// The byte length of the section.
445    pub const fn byte_len(&self) -> usize {
446        unsafe { (self.end as *const u8).offset_from(self.start as *const u8) as usize }
447    }
448
449    /// The number of elements in the section.
450    pub const fn len(&self) -> usize {
451        self.byte_len() / self.stride()
452    }
453
454    /// True if the section is empty.
455    pub const fn is_empty(&self) -> bool {
456        self.len() == 0
457    }
458
459    /// The section as a slice.
460    pub const fn as_slice(&self) -> &[T] {
461        if self.is_empty() {
462            &[]
463        } else {
464            unsafe { ::core::slice::from_raw_parts(self.start_ptr(), self.len()) }
465        }
466    }
467}
468
469impl<'a, T> ::core::iter::IntoIterator for &'a TypedSection<T> {
470    type Item = &'a T;
471    type IntoIter = ::core::slice::Iter<'a, T>;
472    fn into_iter(self) -> Self::IntoIter {
473        self.as_slice().iter()
474    }
475}
476
477impl<T> ::core::ops::Deref for TypedSection<T> {
478    type Target = [T];
479    fn deref(&self) -> &Self::Target {
480        self.as_slice()
481    }
482}
483
484impl<T> ::core::fmt::Debug for TypedSection<T> {
485    fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
486        f.debug_struct("TypedSection")
487            .field("name", &self.name)
488            .field("start", &self.start_ptr())
489            .field("end", &self.end_ptr())
490            .field("len", &self.len())
491            .field("stride", &self.stride())
492            .finish()
493    }
494}
495
496unsafe impl<T> Sync for TypedSection<T> where T: Sync {}
497unsafe impl<T> Send for TypedSection<T> where T: Send {}