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