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