Skip to main content

link_section/
lib.rs

1#![doc = include_str!("../docs/BUILD.md")]
2//! # link-section
3#![doc = include_str!("../docs/PREAMBLE.md")]
4#![allow(unsafe_code)]
5
6/// Declarative forms of the `#[section]` and `#[in_section(...)]` macros.
7///
8/// The declarative forms wrap and parse a proc_macro-like syntax like so, and
9/// are identical in expansion to the undecorated procedural macros. The
10/// declarative forms support the same attribute parameters as the procedural
11/// macros.
12pub mod declarative {
13    pub use crate::__in_section_parse as in_section;
14    pub use crate::__section_parse as section;
15}
16
17#[doc(hidden)]
18pub mod __support {
19    pub use crate::__add_section_link_attribute as add_section_link_attribute;
20    pub use crate::__def_section_name as def_section_name;
21    pub use crate::__get_section as get_section;
22    pub use crate::__in_section_crate as in_section_crate;
23    pub use crate::__in_section_parse as in_section_parse;
24    pub use crate::__section_parse as section_parse;
25
26    #[cfg(feature = "proc_macro")]
27    pub use link_section_proc_macro::hash;
28    #[cfg(feature = "proc_macro")]
29    pub use link_section_proc_macro::ident_concat;
30
31    /// Declares the section_name macro.
32    #[macro_export]
33    #[doc(hidden)]
34    macro_rules! __def_section_name {
35        (
36            {$(
37                $__section:ident $__type:ident => $__prefix:tt __ $__suffix:tt;
38            )*}
39            AUXILIARY = $__aux_sep:literal;
40            MAX_LENGTH = $__max_length:literal;
41            HASH_LENGTH = $__hash_length:literal;
42            VALID_SECTION_CHARS = $__valid_section_chars:literal;
43        ) => {
44            /// Internal macro for generating a section name.
45            #[macro_export]
46            #[doc(hidden)]
47            macro_rules! __section_name {
48                $(
49                    (raw $__section $__type $name:ident) => {
50                        concat!(concat! $__prefix, stringify!($name), concat! $__suffix);
51                    };
52                    (raw $__section $__type $name:ident $aux:ident) => {
53                        concat!(concat! $__prefix, stringify!($name), $__aux_sep, stringify!($aux), concat! $__suffix);
54                    };
55                    ($pattern:tt $__section $__type $name:ident) => {
56                        $crate::__support::hash!($pattern ($__prefix) $name ($__suffix) $__hash_length $__max_length $__valid_section_chars);
57                    };
58                    ($pattern:tt $__section $__type $name:ident $aux:ident) => {
59                        $crate::__support::hash!($pattern ($__prefix) ($name $__aux_sep $aux) ($__suffix) $__hash_length $__max_length $__valid_section_chars);
60                    };
61                )*
62                ($pattern:tt $unknown_section:ident $unknown_type:ident $name:ident) => {
63                    const _: () = {
64                        compile_error!("Unknown section type: `{}`/`{}`", stringify!($unknown_section), stringify!($unknown_type));
65                    };
66                };
67            }
68        };
69    }
70
71    #[cfg(feature = "proc_macro")]
72    #[doc(hidden)]
73    #[macro_export]
74    macro_rules! __add_section_link_attribute(
75        ($section:ident $type:ident $name:ident $($aux:ident)? #[$attr:ident = __] $item:item) => {
76            $crate::__section_name!(
77                (#[$attr = __] #[allow(unsafe_code)] $item)
78                $section $type $name $($aux)?
79            );
80        }
81    );
82
83    #[cfg(not(feature = "proc_macro"))]
84    #[doc(hidden)]
85    #[macro_export]
86    macro_rules! __add_section_link_attribute(
87        ($section:ident $type:ident $name:ident #[$attr:ident = __] $item:item) => {
88            #[$attr = $crate::__section_name!(
89                raw $section $type $name
90            )] $item
91        }
92    );
93
94    // \x01: "do not mangle" (ref https://github.com/rust-lang/rust-bindgen/issues/2935)
95    #[cfg(target_vendor = "apple")]
96    def_section_name! {
97        {
98            data bare =>    ("__DATA,") __ ();
99            code bare =>    ("__TEXT,") __ ();
100            data section => ("__DATA,") __ (",regular,no_dead_strip");
101            code section => ("__TEXT,") __ (",regular,no_dead_strip");
102            data start =>   ("\x01section$start$__DATA$") __ ();
103            data end =>     ("\x01section$end$__DATA$") __ ();
104        }
105        AUXILIARY = "_";
106        MAX_LENGTH = 16;
107        HASH_LENGTH = 6;
108        VALID_SECTION_CHARS = "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
109    }
110
111    #[cfg(target_family = "wasm")]
112    def_section_name! {
113        {
114            data bare =>    (".data", ".link_section.") __ ();
115            data section => (".data", ".link_section.") __ ();
116            code bare =>    (".text", ".link_section.") __ ();
117            code section => (".text", ".link_section.") __ ();
118        }
119        AUXILIARY = ".";
120        MAX_LENGTH = 16;
121        HASH_LENGTH = 6;
122        VALID_SECTION_CHARS = "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
123    }
124
125    #[cfg(all(
126        not(target_vendor = "apple"),
127        not(target_vendor = "pc"),
128        not(target_family = "wasm")
129    ))]
130    def_section_name! {
131        {
132            data bare =>    ("_data", "_link_section_") __ ();
133            data section => ("_data", "_link_section_") __ ();
134            data start =>   ("__start_", "_data", "_link_section_") __ ();
135            data end =>     ("__stop_", "_data", "_link_section_") __ ();
136            code bare =>    ("_text", "_link_section_") __ ();
137            code section => ("_text", "_link_section_") __ ();
138            code start =>   ("__start_", "_text", "_link_section_") __ ();
139            code end =>     ("__stop_", "_text", "_link_section_") __ ();
140        }
141        AUXILIARY = "_";
142        MAX_LENGTH = 64;
143        HASH_LENGTH = 10;
144        VALID_SECTION_CHARS = "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
145    }
146
147    #[cfg(target_vendor = "pc")]
148    def_section_name! {
149        {
150            data bare =>    (".data", "$") __ ();
151            data section => (".data", "$") __ ("$b");
152            data start =>   (".data", "$") __ ("$a");
153            data end =>     (".data", "$") __ ("$c");
154            code bare =>    (".text", "$") __ ();
155            code section => (".text", "$") __ ("$b");
156            code start =>   (".text", "$") __ ("$a");
157            code end =>     (".text", "$") __ ("$c");
158        }
159        AUXILIARY = "$d$";
160        MAX_LENGTH = 64;
161        HASH_LENGTH = 10;
162        VALID_SECTION_CHARS = "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
163    }
164
165    #[cfg(not(feature = "proc_macro"))]
166    #[doc(hidden)]
167    #[macro_export]
168    macro_rules! __declare_macro {
169        ($vis:vis $ident:ident $generic_macro:ident $args:tt) => {
170            /// Internal macro for parsing the section. This is exported with
171            /// the same name as the type below.
172            #[doc(hidden)]
173            $vis use $crate::$generic_macro as $ident;
174        };
175    }
176
177    #[cfg(feature = "proc_macro")]
178    #[doc(hidden)]
179    #[macro_export]
180    macro_rules! __declare_macro {
181        ($vis:vis $ident:ident $generic_macro:ident $args:tt) => {
182            $crate::__support::ident_concat!(
183                (#[macro_export]
184                #[doc(hidden)]
185                macro_rules!)  (__ $ident __link_section_private_macro__) ({
186                    ($passthru:tt) => {
187                        $crate::$generic_macro!($passthru $args);
188                    };
189                })
190            );
191
192            $crate::__support::ident_concat!(
193                (#[doc(hidden)] pub use) (__ $ident __link_section_private_macro__) (as $ident;)
194            );
195        }
196    }
197
198    /// Define a link section.
199    #[macro_export]
200    #[doc(hidden)]
201    macro_rules! __section_parse {
202        // Has a generic (note that $generic eats the trailing semicolon)
203        (#[section $($args:tt)*] $(#[$meta:meta])* $vis:vis static $ident:ident : $(:: $path_prefix:ident ::)? $($path:ident)::* < $($generic:tt)*) => {
204            $crate::__section_parse!(@parsed #[section $($args)*] $(#[$meta])* $vis static $ident: ( $(:: $path_prefix ::)? $($path)::* < $($generic)*) ( $($generic)* ) __in_section_helper_macro_generic);
205        };
206        // No generic
207        (#[section $($args:tt)*] $(#[$meta:meta])* $vis:vis static $ident:ident : $(:: $path_prefix:ident ::)? $($path:ident)::* ;) => {
208            $crate::__section_parse!(@parsed #[section $($args)*] $(#[$meta])* $vis static $ident: ( $(:: $path_prefix ::)? $($path)::* ;) ( () > ; ) __in_section_helper_macro_no_generic);
209        };
210        // Both end up here...
211        (@parsed #[section(aux = $name:ident, no_macro)] $(#[$meta:meta])* $vis:vis static $ident:ident : ($ty:ty ;) ( $generic_ty:ty > ; ) $generic_macro:ident) => {
212            $crate::__section_parse!(@generate #[section(aux = $name)] $(#[$meta])* $vis static $ident: $ty, $generic_ty, $generic_macro);
213        };
214        (@parsed #[section(no_macro)] $(#[$meta:meta])* $vis:vis static $ident:ident : ($ty:ty ;) ( $generic_ty:ty > ; ) $generic_macro:ident) => {
215            $crate::__section_parse!(@generate #[section] $(#[$meta])* $vis static $ident: $ty, $generic_ty, $generic_macro);
216        };
217        (@parsed #[section $($args:tt)*] $(#[$meta:meta])* $vis:vis static $ident:ident : ($ty:ty ;) ( $generic_ty:ty > ; ) $generic_macro:ident) => {
218            $crate::__declare_macro!($vis $ident $generic_macro ($($args)*));
219            $crate::__section_parse!(@generate #[section $($args)*] $(#[$meta])* $vis static $ident: $ty, $generic_ty, $generic_macro);
220        };
221        (@generate #[section $($args:tt)*] $(#[$meta:meta])* $vis:vis static $ident:ident : $ty:ty, $generic_ty:ty, __in_section_helper_macro_generic) => {
222            $crate::__section_parse!(@generate #[section $($args)*] $(#[$meta])* $vis static $ident: $ty, $generic_ty, __base_case__);
223
224            impl ::core::iter::IntoIterator for $ident {
225                type Item = &'static $generic_ty;
226                type IntoIter = ::core::slice::Iter<'static, $generic_ty>;
227                fn into_iter(self) -> Self::IntoIter {
228                    $ident.as_slice().iter()
229                }
230            }
231        };
232        (@generate #[section $($args:tt)*] $(#[$meta:meta])* $vis:vis static $ident:ident : $ty:ty, $generic_ty:ty, $generic_macro:ident) => {
233            $(#[$meta])*
234            #[allow(non_camel_case_types)]
235            $vis struct $ident;
236
237            impl $crate::__support::SectionItemType for $ident {
238                type Item = $generic_ty;
239            }
240
241            impl ::core::fmt::Debug for $ident {
242                fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
243                    ::core::ops::Deref::deref(self).fmt(f)
244                }
245            }
246
247            impl ::core::ops::Deref for $ident {
248                type Target = $ty;
249                fn deref(&self) -> &Self::Target {
250                    self.const_deref()
251                }
252            }
253
254            $crate::__section_parse!(@deref #[section $($args)*] $(#[$meta])* $vis static $ident: $ty, $generic_ty, __base_case__);
255        };
256        (@deref #[section] $(#[$meta:meta])* $vis:vis static $ident:ident : $ty:ty, $generic_ty:ty, __base_case__) => {
257            impl $ident {
258                /// Get a `const` reference to the underlying section. In
259                /// non-const contexts, `deref` is sufficient.
260                pub const fn const_deref(&self) -> &$ty {
261                    static SECTION: $ty = {
262                        let section = $crate::__support::get_section!(name=$ident, type=$generic_ty, aux=);
263                        let name = $crate::__section_name!(
264                            raw data bare $ident
265                        );
266                        unsafe { <$ty>::new(name, section.0, section.1) }
267                    };
268                    &SECTION
269                }
270            }
271        };
272        (@deref #[section(aux=$aux:ident)] $(#[$meta:meta])* $vis:vis static $ident:ident : $ty:ty, $generic_ty:ty, __base_case__) => {
273            impl $ident {
274                /// Get a `const` reference to the underlying section. In
275                /// non-const contexts, `deref` is sufficient.
276                pub const fn const_deref(&self) -> &$ty {
277                    static SECTION: $ty = {
278                        let section = $crate::__support::get_section!(name=$ident, type=$generic_ty, aux=$aux);
279                        let name = $crate::__section_name!(
280                            raw data bare $aux $ident // swap
281                        );
282                        unsafe { <$ty>::new(name, section.0, section.1) }
283                    };
284                    &SECTION
285                }
286            }
287        };
288    }
289
290    #[cfg(miri)]
291    mod section {
292        #[doc(hidden)]
293        #[macro_export]
294        macro_rules! __get_section {
295            (name=$ident:ident, type=$generic_ty:ty, aux=$($aux:ident)?) => {{
296                (std::ptr::null_mut(), std::ptr::null_mut())
297            }};
298        }
299
300        /// On Apple platforms, the linker provides a pointer to the start and end
301        /// of the section regardless of the section's name.
302        pub type SectionPtr<T> = *const ::core::marker::PhantomData<T>;
303    }
304
305    #[cfg(all(not(miri), target_family = "wasm"))]
306    mod section {
307        #[doc(hidden)]
308        #[macro_export]
309        macro_rules! __get_section {
310            (name=$ident:ident, type=$generic_ty:ty, aux=$($aux:ident)?) => {
311                {
312                    static __START: ::core::sync::atomic::AtomicPtr::<::core::marker::PhantomData<$generic_ty>> = unsafe {
313                        ::core::sync::atomic::AtomicPtr::<::core::marker::PhantomData<$generic_ty>>::new(::core::ptr::null_mut())
314                    };
315                    static __END: ::core::sync::atomic::AtomicPtr::<::core::marker::PhantomData<$generic_ty>> = unsafe {
316                        ::core::sync::atomic::AtomicPtr::<::core::marker::PhantomData<$generic_ty>>::new(::core::ptr::null_mut())
317                    };
318
319                    $crate::__support::ident_concat!((#[no_mangle]pub extern "C" fn) (register_link_section_ $ident) ((data_ptr: *const u8, data_len: usize) {
320                        unsafe {
321                            __START.store(data_ptr as *mut ::core::marker::PhantomData<$generic_ty>, ::core::sync::atomic::Ordering::Relaxed);
322                            __END.store(data_ptr.add(data_len) as *mut ::core::marker::PhantomData<$generic_ty>, ::core::sync::atomic::Ordering::Relaxed);
323                        }
324                    }));
325
326                    (&__START, &__END)
327                }
328            }
329        }
330
331        /// On WASM, we use an atomic pointer to the start and end of the
332        /// section. The host environment is responsible for registering the
333        /// section with the runtime.
334        pub type SectionPtr<T> =
335            &'static ::core::sync::atomic::AtomicPtr<::core::marker::PhantomData<T>>;
336    }
337
338    #[cfg(all(not(miri), target_vendor = "pc"))]
339    mod section {
340        #[doc(hidden)]
341        #[macro_export]
342        macro_rules! __get_section {
343            (name=$ident:ident, type=$generic_ty:ty, aux=$($aux:ident)?) => {
344                {
345                    $crate::__support::add_section_link_attribute!(
346                        data start $ident $($aux)?
347                        #[link_section = __]
348                        static __START: [$generic_ty; 0] = [];
349                    );
350                    $crate::__support::add_section_link_attribute!(
351                        data end $ident $($aux)?
352                        #[link_section = __]
353                        static __END: [$generic_ty; 0] = [];
354                    );
355
356                    (
357                        unsafe { &raw const __START as $crate::__support::SectionPtr<$generic_ty> },
358                        unsafe { &raw const __END as $crate::__support::SectionPtr<$generic_ty> },
359                    )
360                }
361            }
362        }
363
364        /// On Windows platforms we don't have start/end symbols, but we do have
365        /// section sorting so we drop a [T; 0] at the start and end of the
366        /// section.
367        pub type SectionPtr<T> = *const [T; 0];
368    }
369
370    #[cfg(all(not(miri), not(target_family = "wasm"), not(target_vendor = "pc")))]
371    mod section {
372        #[doc(hidden)]
373        #[macro_export]
374        macro_rules! __get_section {
375            (name=$ident:ident, type=$generic_ty:ty, aux=$($aux:ident)?) => {
376                {
377                    extern "C" {
378                        $crate::__support::add_section_link_attribute!(
379                            data start $ident $($aux)?
380                            #[link_name = __]
381                            static __START: $crate::__support::SectionPtr<$generic_ty>;
382                        );
383                    }
384                    extern "C" {
385                        $crate::__support::add_section_link_attribute!(
386                            data end $ident $($aux)?
387                            #[link_name = __]
388                            static __END: $crate::__support::SectionPtr<$generic_ty>;
389                        );
390                    }
391
392                    (
393                        unsafe { &raw const __START as $crate::__support::SectionPtr<$generic_ty> },
394                        unsafe { &raw const __END as $crate::__support::SectionPtr<$generic_ty> },
395                    )
396                }
397            }
398        }
399
400        /// On LLVM/GCC platforms we can use orphan sections with _start and
401        /// _end symbols.
402        pub type SectionPtr<T> = *const ::core::marker::PhantomData<T>;
403    }
404
405    /// Export a symbol into a link section.
406    #[macro_export]
407    #[doc(hidden)]
408    macro_rules! __in_section_parse {
409        // Needs to handle:
410        //  <name>
411        //  :: <name>
412        //  <path> :: <name>
413        //  :: <path> :: <name>
414        //  etc...
415        (#[in_section(unsafe, type = $stored_ty:ty, name = $ident:ident $( , aux = $aux:ident)?)] $($item:tt)*) => {
416            $crate::__support::in_section_crate!((type = $stored_ty), $ident, $($aux)?, $ident, ($($item)*));
417        };
418        (#[in_section(unsafe, name = $ident:ident $( , aux = $aux:ident)?)] $($item:tt)*) => {
419            $crate::__support::in_section_crate!(data, $ident, $($aux)?, $ident, ($($item)*));
420        };
421        (#[in_section( $($path:tt)* )] $($item:tt)*) => {
422            $crate::__support::in_section_parse!(path=[$($path)*] #[in_section($($path)*)] $($item)*);
423        };
424        (path=[$orig_path:path] #[in_section($name:ident)] $($item:tt)*) => {
425            $orig_path ! (
426                (v=0 (name=$name (path=[$orig_path] (item=($($item)*) ()))))
427            );
428        };
429        (path=[$orig_path:path] #[in_section(:: $($path:ident)::*)] $($item:tt)*) => {
430            $crate::__support::in_section_parse!(path=[$orig_path] #[in_section($($path)::*)] $($item)*);
431        };
432        (path=[$orig_path:path] #[in_section($prefix:ident :: $($path:ident)::*)] $($item:tt)*) => {
433            $crate::__support::in_section_parse!(path=[$orig_path] #[in_section($($path)::*)] $($item)*);
434        };
435    }
436
437    #[macro_export]
438    #[doc(hidden)]
439    macro_rules! __in_section_helper_macro_generic {
440        ((v=0 (name=$ident:ident (path=[$path:path] (item=$item:tt $rest:tt))))) => {
441            $crate::__support::in_section_crate!(section, $ident,, $path, $item);
442        };
443        ((v=0 (name=$ident:ident (path=[$path:path] (item=$item:tt $rest:tt)))) ((aux=$aux:ident)) )=> {
444            $crate::__support::in_section_crate!(section, $ident, $aux, $path, $item);
445        };
446        ((v=0 (name=$ident:ident (path=[$path:path] (item=$item:tt $rest:tt)))) () )=> {
447            $crate::__support::in_section_crate!(section, $ident,, $path, $item);
448        };
449        (v=$v:literal $rest:tt) => {
450            const _: () = {
451                compile_error!(concat!(
452                    "link-section: Unsupported version: `",
453                    stringify!($v),
454                    "`: ",
455                    stringify!($rest)
456                ));
457            };
458        };
459    }
460
461    #[macro_export]
462    #[doc(hidden)]
463    macro_rules! __in_section_helper_macro_no_generic {
464        ((v=0 (name=$ident:ident (path=[$path:path] (item=$item:tt $rest:tt))))) => {
465            $crate::__support::in_section_crate!(data, $ident,, $path, $item);
466        };
467        ((v=0 (name=$ident:ident (path=[$path:path] (item=$item:tt $rest:tt)))) ((aux=$aux:ident)) )=> {
468            $crate::__support::in_section_crate!(data, $ident, $aux, $path, $item);
469        };
470        ((v=0 (name=$ident:ident (path=[$path:path] (item=$item:tt $rest:tt)))) () )=> {
471            $crate::__support::in_section_crate!(data, $ident,, $path, $item);
472        };
473        (v=$v:literal $rest:tt) => {
474            const _: () = {
475                compile_error!(concat!(
476                    "link-section: Unsupported version: `",
477                    stringify!($v),
478                    "`: ",
479                    stringify!($rest)
480                ));
481            };
482        };
483    }
484
485    #[macro_export]
486    #[doc(hidden)]
487    #[allow(unknown_lints, edition_2024_expr_fragment_specifier)]
488    macro_rules! __in_section_crate {
489        (@type_select section $path:path, $item_ty:ty) => {
490            <$path as $crate::__support::SectionItemType>::Item
491        };
492        (@type_select data $path:path, $item_ty:ty) => {
493            $item_ty
494        };
495        (@type_select (type = $stored_ty:ty) $path:path, $item_ty:ty) => {
496            $stored_ty
497        };
498        ($type_source:tt, $ident:ident, $($aux:ident)?, $path:path, ($(#[$meta:meta])* $vis:vis fn $ident_fn:ident($($args:tt)*) $(-> $ret:ty)? $body:block)) => {
499            $crate::__add_section_link_attribute!(
500                data section $ident $($aux)?
501                #[link_section = __]
502                $(#[$meta])*
503                #[used]
504                #[allow(non_upper_case_globals)]
505                $vis static $ident_fn: $crate::__in_section_crate!(@type_select $type_source $path, fn($($args)*) $(-> $ret)?) =
506                    {
507                        $crate::__add_section_link_attribute!(
508                            code section $ident $($aux)?
509                            #[link_section = __]
510                            fn $ident_fn($($args)*) $(-> $ret)? $body
511                        );
512                        $ident_fn
513                    };
514            );
515        };
516        ($type_source:tt, $ident:ident, $($aux:ident)?, $path:path, ($(#[$meta:meta])* $vis:vis static _ : $ty:ty = $value:expr;)) => {
517            const _: () = {
518                $crate::__add_section_link_attribute!(
519                    data section $ident $($aux)?
520                    #[link_section = __]
521                    $(#[$meta])* #[used] $vis static ANONYMOUS: $crate::__in_section_crate!(@type_select $type_source $path, $ty) = $value;
522                );
523            };
524        };
525        ($type_source:tt, $ident:ident, $($aux:ident)?, $path:path, ($(#[$meta:meta])* $vis:vis static $ident_static:ident : $ty:ty = $value:expr;)) => {
526            $crate::__add_section_link_attribute!(
527                data section $ident $($aux)?
528                #[link_section = __]
529                $(#[$meta])* #[used] $vis static $ident_static: $crate::__in_section_crate!(@type_select $type_source $path, $ty) = $value;
530            );
531        };
532        (data, $ident:ident, $($aux:ident)?, $path:path, ($(#[$meta:meta])* $item:item)) => {
533            $crate::__add_section_link_attribute!(
534                data section $ident $($aux)?
535                #[link_section = __]
536                $(#[$meta])* #[used] $item
537            );
538        };
539    }
540
541    pub trait SectionItemType {
542        type Item;
543    }
544
545    impl<T> SectionItemType for super::TypedSection<T> {
546        type Item = T;
547    }
548
549    pub use section::SectionPtr;
550}
551
552/// Define a link section.
553///
554/// The definition site generates two items: a static section struct that is
555/// used to access the section, and a macro that is used to place items into the
556/// section. The macro is used by the [`in_section`] procedural macro.
557///
558/// # Attributes
559///
560/// - `no_macro`: Does not generate the submission macro at the definition site.
561///   This will require any associated [`in_section`] invocations to use the raw
562///   name of the section.
563/// - `aux = <name>`: Specifies that this section is an auxiliary section, and
564///   that the section is named `<name>+<aux>`.
565///
566/// # Example
567/// ```rust
568/// use link_section::{in_section, section};
569///
570/// #[section]
571/// pub static DATA_SECTION: link_section::Section;
572///
573/// #[in_section(DATA_SECTION)]
574/// pub fn data_function() {
575///     println!("data_function");
576/// }
577/// ```
578#[cfg(feature = "proc_macro")]
579pub use ::link_section_proc_macro::section;
580
581/// Place an item into a link section.
582///
583/// # Functions and typed sections
584///
585/// As a special case, since function declarations by themselves are not sized,
586/// functions in typed sections are split and stored as function pointers.
587#[cfg(feature = "proc_macro")]
588pub use ::link_section_proc_macro::in_section;
589
590/// An untyped link section that can be used to store any type. The underlying
591/// data is not enumerable.
592#[repr(C)]
593pub struct Section {
594    name: &'static str,
595    start: __support::SectionPtr<()>,
596    end: __support::SectionPtr<()>,
597}
598
599impl Section {
600    #[doc(hidden)]
601    pub const unsafe fn new(
602        name: &'static str,
603        start: __support::SectionPtr<()>,
604        end: __support::SectionPtr<()>,
605    ) -> Self {
606        Self { name, start, end }
607    }
608
609    /// The byte length of the section.
610    pub fn byte_len(&self) -> usize {
611        unsafe { (self.end_ptr() as *const u8).offset_from(self.start_ptr() as *const u8) as usize }
612    }
613}
614
615#[cfg(target_family = "wasm")]
616impl Section {
617    /// The start address of the section.
618    pub fn start_ptr(&self) -> *const () {
619        let ptr = self.start.load(::core::sync::atomic::Ordering::Relaxed) as *const ();
620        if ptr.is_null() {
621            panic!(
622                "Section {} was not initialized by the host environment",
623                self.name
624            );
625        }
626        ptr
627    }
628    /// The end address of the section.
629    pub fn end_ptr(&self) -> *const () {
630        let ptr = self.end.load(::core::sync::atomic::Ordering::Relaxed) as *const ();
631        if ptr.is_null() {
632            panic!(
633                "Section {} was not initialized by the host environment",
634                self.name
635            );
636        }
637        ptr
638    }
639}
640
641#[cfg(not(target_family = "wasm"))]
642impl Section {
643    /// The start address of the section.
644    pub fn start_ptr(&self) -> *const () {
645        self.start as *const ()
646    }
647    /// The end address of the section.
648    pub fn end_ptr(&self) -> *const () {
649        self.end as *const ()
650    }
651}
652
653impl ::core::fmt::Debug for Section {
654    fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
655        f.debug_struct("Section")
656            .field("name", &self.name)
657            .field("start", &self.start_ptr())
658            .field("end", &self.end_ptr())
659            .field("byte_len", &self.byte_len())
660            .finish()
661    }
662}
663
664unsafe impl Sync for Section {}
665unsafe impl Send for Section {}
666
667/// A typed link section that can be used to store any sized type. The
668/// underlying data is enumerable.
669#[repr(C)]
670pub struct TypedSection<T: 'static> {
671    name: &'static str,
672    start: __support::SectionPtr<T>,
673    end: __support::SectionPtr<T>,
674    _phantom: ::core::marker::PhantomData<T>,
675}
676
677#[cfg(target_family = "wasm")]
678impl<T: 'static> TypedSection<T> {
679    /// The start address of the section.
680    pub fn start_ptr(&self) -> *const T {
681        let ptr = self.start.load(::core::sync::atomic::Ordering::Relaxed) as *const T;
682        if ptr.is_null() {
683            panic!(
684                "TypedSection {} was not initialized by the host environment",
685                self.name
686            );
687        }
688        ptr
689    }
690
691    /// The end address of the section.
692    pub fn end_ptr(&self) -> *const T {
693        let ptr = self.end.load(::core::sync::atomic::Ordering::Relaxed) as *const T;
694        if ptr.is_null() {
695            panic!(
696                "TypedSection {} was not initialized by the host environment",
697                self.name
698            );
699        }
700        ptr
701    }
702}
703
704#[cfg(not(target_family = "wasm"))]
705impl<T: 'static> TypedSection<T> {
706    /// The start address of the section.
707    pub fn start_ptr(&self) -> *const T {
708        self.start as usize as *const T
709    }
710
711    /// The end address of the section.
712    pub fn end_ptr(&self) -> *const T {
713        self.end as *const T
714    }
715}
716
717// Non-const, shared functions (or functions that don't depend on the pointers)
718impl<T: 'static> TypedSection<T> {
719    #[doc(hidden)]
720    pub const unsafe fn new(
721        name: &'static str,
722        start: __support::SectionPtr<T>,
723        end: __support::SectionPtr<T>,
724    ) -> Self {
725        Self {
726            name,
727            start,
728            end,
729            _phantom: ::core::marker::PhantomData,
730        }
731    }
732
733    /// The stride of the typed section.
734    pub const fn stride(&self) -> usize {
735        assert!(
736            ::core::mem::size_of::<T>() > 0
737                && ::core::mem::size_of::<T>() * 2 == ::core::mem::size_of::<[T; 2]>()
738        );
739        ::core::mem::size_of::<T>()
740    }
741
742    /// The byte length of the section.
743    pub fn byte_len(&self) -> usize {
744        unsafe { (self.end_ptr() as *const u8).offset_from(self.start_ptr() as *const u8) as usize }
745    }
746
747    /// The number of elements in the section.
748    pub fn len(&self) -> usize {
749        self.byte_len() / self.stride()
750    }
751
752    /// True if the section is empty.
753    pub fn is_empty(&self) -> bool {
754        self.len() == 0
755    }
756
757    /// The section as a slice.
758    pub fn as_slice(&self) -> &[T] {
759        if self.is_empty() {
760            &[]
761        } else {
762            unsafe { ::core::slice::from_raw_parts(self.start_ptr(), self.len()) }
763        }
764    }
765
766    /// The offset of the item in the section, if it is in the section.
767    pub fn offset_of(&self, item: &T) -> Option<usize> {
768        let ptr = item as *const T;
769        if ptr < self.start_ptr() || ptr >= self.end_ptr() {
770            None
771        } else {
772            Some(unsafe { ptr.offset_from(self.start_ptr()) as usize })
773        }
774    }
775
776    /// The section as a mutable slice.
777    ///
778    /// # Safety
779    ///
780    /// This cannot be safely used and is _absolutely unsound_ if any other
781    /// slices are live.
782    #[allow(clippy::mut_from_ref)]
783    pub unsafe fn as_mut_slice(&self) -> &mut [T] {
784        if self.is_empty() {
785            &mut []
786        } else {
787            unsafe { ::core::slice::from_raw_parts_mut(self.start_ptr() as *mut T, self.len()) }
788        }
789    }
790}
791
792impl<'a, T> ::core::iter::IntoIterator for &'a TypedSection<T> {
793    type Item = &'a T;
794    type IntoIter = ::core::slice::Iter<'a, T>;
795    fn into_iter(self) -> Self::IntoIter {
796        self.as_slice().iter()
797    }
798}
799
800impl<T> ::core::ops::Deref for TypedSection<T> {
801    type Target = [T];
802    fn deref(&self) -> &Self::Target {
803        self.as_slice()
804    }
805}
806
807impl<T> ::core::fmt::Debug for TypedSection<T> {
808    fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
809        f.debug_struct("TypedSection")
810            .field("name", &self.name)
811            .field("start", &self.start_ptr())
812            .field("end", &self.end_ptr())
813            .field("len", &self.len())
814            .field("stride", &self.stride())
815            .finish()
816    }
817}
818
819unsafe impl<T> Sync for TypedSection<T> where T: Sync {}
820unsafe impl<T> Send for TypedSection<T> where T: Send {}