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#![doc = include_str!("../docs/REEXPORT.md")]
5#![doc = include_str!("../docs/GENERATED.md")]
6#![allow(unsafe_code)]
7#![no_std]
8#![recursion_limit = "256"]
9
10#[doc = include_str!("../docs/LIFE_BEFORE_MAIN.md")]
11pub mod life_before_main {}
12
13mod item;
14mod macros;
15mod meta;
16mod platform;
17mod section_parse;
18mod sections;
19
20pub use item::SectionItemLocation;
21pub use sections::{
22    MovableBackref, MovableRef, Ref, Section, TypedMovableSection, TypedMutableSection,
23    TypedReferenceSection, TypedSection,
24};
25
26/// Types for [`TypedReferenceSection`].
27#[deprecated(since = "0.17.1", note = "Use [`Ref`] from the crate root instead.")]
28pub mod reference {
29    pub use crate::sections::Ref;
30}
31
32__declare_features!(
33    section: __section_features;
34
35    @default: type;
36
37    /// Auxiliary sections are stored in a section near the main section. The
38    /// aux path must be a valid reference to the main section.
39    aux {
40        attr: [(aux(main = $($aux_name:tt)*)) => (($($aux_name)*))];
41        example: "aux(main = path::to::MAIN_SECTION)";
42        validate: [(($aux_name:path))];
43    };
44    /// The path to the `link-section` crate containing the support macros. If
45    /// you re-export `link-section` items as part of your crate, you can use
46    /// this to redirect the macro's output to the correct crate.
47    ///
48    /// Using the declarative [`section!`][s] form is
49    /// preferred over this parameter.
50    ///
51    /// [s]: crate::declarative::section!
52    crate_path {
53        attr: [(crate_path = $path:pat) => (($path))];
54        example: "crate_path = ::path::to::link_section";
55    };
56    /// Specify a custom section name to allow the section to be used without a
57    /// direct reference. If not specified, the section name will be generated
58    /// using the item name and a path to the section.
59    ///
60    /// It is valid to specify multiple sections with the same name, and the linker
61    /// will ensure that both sections contain the same items. The multiple sections
62    /// must contain the same type, otherwise the section will `panic!` at runtime.
63    ///
64    /// While `name` accepts a path, this path does not refer to a specific Rust
65    /// item path.
66    name {
67        attr: [(name = $($name_path:tt)*) => (($($name_path)*))];
68        example: "name = my_crate::SECTION_NAME";
69        validate: [(($name_path:path))];
70    };
71    /// Crate feature `proc_macro` (enables the `#[section]` attribute shim).
72    proc_macro {
73        feature: "proc_macro";
74    };
75    /// The type of the section.
76    type {
77        attr: [
78            (type = $section_type:ident) => ($section_type)
79        ];
80        example: "untyped | typed | mutable | movable | reference";
81        validate: [(untyped), (typed), (mutable), (movable), (reference)];
82    };
83    /// Allow the section to be used without a direct reference.
84    unsafe {
85        attr: [(unsafe) => (unsafe)];
86    };
87);
88
89#[cfg(doc)]
90__generate_docs!(__section_features);
91
92__declare_features!(
93    in_section: __in_section_features;
94
95    @default: section;
96
97    /// Specify an auxiliary section name to allow submission without a direct
98    /// reference. Requires `unsafe`.
99    aux {
100        attr: [(aux(main = $($aux_name:tt)*)) => (($($aux_name)*))];
101        example: "aux(main = my_crate::SECTION_NAME)";
102        validate: [(($aux_name:path))];
103    };
104    /// Specify a custom section name to allow submission without a direct
105    /// reference. Requires `unsafe`.
106    ///
107    /// While `name` accepts a path, this path does not refer to a specific Rust
108    /// item path.
109    name {
110        attr: [(name = $($name_path:tt)*) => (($($name_path)*))];
111        example: "name = my_crate::SECTION_NAME";
112        validate: [(($name_is_path:path))];
113    };
114    /// Specify an ordinary section reference. The path must be a valid
115    /// reference to the section.
116    section {
117        attr: [(section = $($section_path:tt)*) => (($($section_path)*))];
118        example: "[section = ] ::path::to::SECTION";
119        validate: [(($section_path:path))];
120    };
121    /// Specify the type of the section. Used for unsafe submission.
122    section_type {
123        attr: [(type = $section_type_name:ident) => ($section_type_name)];
124        example: "type = untyped | typed | mutable | movable | reference";
125        validate: [(untyped), (typed), (mutable), (movable), (reference)];
126    };
127    unsafe {
128        attr: [(unsafe) => (unsafe)];
129    };
130);
131
132#[cfg(target_family = "wasm")]
133extern crate alloc;
134
135/// Declarative forms of the `#[section]` and `#[in_section(...)]` macros.
136///
137/// The declarative forms wrap and parse a proc_macro-like syntax like so, and
138/// are identical in expansion to the undecorated procedural macros. The
139/// declarative forms support the same attribute parameters as the procedural
140/// macros.
141pub mod declarative {
142    pub use crate::__in_section_parse as in_section;
143    pub use crate::__section_parse as section;
144}
145
146#[doc(hidden)]
147pub mod __support {
148    pub use crate::__add_section_link_attribute as add_section_link_attribute;
149    pub use crate::__in_section_crate as in_section_crate;
150    pub use crate::__in_section_parse as in_section_parse;
151    pub use crate::__section_parse as section_parse;
152
153    pub use crate::sections::IsUntypedSection;
154    pub use crate::{item::*, platform::*};
155
156    #[cfg(feature = "proc_macro")]
157    pub use linktime_proc_macro::combine;
158
159    #[doc(hidden)]
160    #[macro_export]
161    macro_rules! __hash_no_proc_macro {
162        (unsafe (($($__prefix:literal)*)) (($($name:ident)::*) $($literal2:literal ($($name2:ident)::*))?) (($($__suffix:literal)*)) $__hash_length:literal $__max_length:literal $__valid_section_chars:literal) => {
163            concat!($($__prefix,)* $(stringify!($name)),* $( ,$literal2 $(, stringify!($name2))* )? $(,$__suffix)*)
164        };
165        ($($rest:tt)*) => {
166            compile_error!(concat!("link-section: No proc_macro feature enabled: `unsafe` is required", stringify!($($rest)*)));
167        };
168    }
169
170    #[doc(hidden)]
171    #[macro_export]
172    macro_rules! __hash_proc_macro {
173        // Unsafe sections are hashed if and only if the name is not valid for
174        // the platform.
175        (unsafe $prefix:tt $name:tt $suffix:tt $hash_length:literal $max_length:literal $valid_section_chars:literal) => {
176            $crate::__support::combine!(output=string input=(
177                __IF__(
178                    test=(
179                        __LE__(
180                            a=(__LENGTH__(string=(
181                                __TOIDENT__(input=(__RAW__(input=($name))))
182                            )))
183                            b=$max_length
184                        )
185                    )
186                    then=(
187                        $prefix
188                        __TOIDENT__(input=(__RAW__(input=($name))))
189                        $suffix
190                    )
191                    else=(
192                        $prefix
193                        __SUBSTRING__(input=(
194                            __TOIDENT__(input=(__RAW__(input=($name))))
195                        ) end=(__SUB__(a=$max_length b=$hash_length)))
196                        __SUBSTRING__(input=(
197                            __HASH__(string=(__RAW__(input=($name))))
198                        ) length=$hash_length)
199                        $suffix
200                    )
201                )
202            ))
203        };
204        // Safe sections are always hashed. Note: `ignore_base` below avoids
205        // churn on the expansion tests.
206        ($definition:tt $prefix:tt $name:tt $suffix:tt $hash_length:literal $max_length:literal $valid_section_chars:literal) => {
207            $crate::__support::combine!(output=string input=(
208                $prefix
209                __SUBSTRING__(input=(
210                    __SUBSTRING__(input=(
211                        __TOIDENT__(input=(__RAW__(input=($name))))
212                    ) end=(__SUB__(a=$max_length b=$hash_length)))
213                    __LOCATIONHASH__(of=($definition $name) alphabet=[_0-9a-zA-Z] ignore_base=("src/lib.rs"))
214                ) length=$max_length)
215                $suffix
216            ))
217        };
218    }
219
220    #[cfg(feature = "proc_macro")]
221    pub use __hash_proc_macro as hash;
222
223    #[cfg(not(feature = "proc_macro"))]
224    pub use __hash_no_proc_macro as hash;
225
226    #[cfg(miri)]
227    #[doc(hidden)]
228    #[macro_export]
229    macro_rules! __address_of_symbol {
230        ($ref_or_item:ident $section:ident $type:ident $name:tt) => {
231            // Miri does not support any of these linker-defined extern statics
232            // see: https://github.com/rust-lang/miri/blob/master/src/shims/extern_static.rs#L15
233            ::core::ptr::null() as *const ()
234        };
235    }
236
237    #[cfg(not(miri))]
238    #[doc(hidden)]
239    #[macro_export]
240    macro_rules! __address_of_symbol {
241        ($ref_or_item:ident $section:ident $type:ident $name:tt) => {
242            {
243                // These are not valid items, but they are valid pointers.
244                // We cannot safely use them - only take pointers to them.
245                $crate::__add_linktime_attributes_to_static!(
246                    extern "C" {
247                        #[link_name = $crate::__support::section_name!(string $ref_or_item $section $type $name)]
248                        static __SYMBOL: u8;
249                    }
250                );
251                // TODO: black_box when hint is stable
252                // TODO: MSRV: we can use &raw const once we bump MSRV
253                // unsafe { &raw const __SYMBOL as *const () }
254                unsafe { ::core::ptr::addr_of!(__SYMBOL) as *const () }
255            }
256        }
257    }
258
259    #[doc(hidden)]
260    #[macro_export]
261    macro_rules! __add_section_link_attribute(
262        ($ref_or_item:ident $section:ident $type:ident $name:tt #[$attr:ident = __]
263            $(#[$meta:meta])*
264            $vis:vis static $($static:tt)*
265        ) => {
266            $crate::__add_linktime_attributes_to_static!(
267                #[$attr = $crate::__support::section_name!(string $ref_or_item $section $type $name)]
268                $(#[$meta])*
269                $vis static $($static)*
270            );
271        };
272        ($ref_or_item:ident $section:ident $type:ident $name:tt #[$attr:ident = __]
273            extern "C" {
274                $(#[$meta:meta])*
275                $vis:vis static $($static:tt)*
276            }
277        ) => {
278            $crate::__add_linktime_attributes_to_static!(
279                extern "C" {
280                    #[link_name = $crate::__support::section_name!(string $ref_or_item $section $type $name)]
281                    $(#[$meta])*
282                    $vis static $($static)*
283                }
284            );
285        };
286        ($ref_or_item:ident $section:ident $type:ident $name:tt #[$attr:ident = __]
287            $($item:tt)*) => {
288            $crate::__add_linktime_attributes_to_static!(
289                #[$attr = $crate::__support::section_name!(string $ref_or_item $section $type $name)]
290                $($item)*
291            );
292        };
293    );
294
295    #[cfg(target_family = "wasm")]
296    #[macro_export]
297    #[doc(hidden)]
298    macro_rules! __if_wasm {
299        (($($true:tt)*) ($($false:tt)*)) => {
300            $($true)*
301        };
302    }
303
304    #[cfg(not(target_family = "wasm"))]
305    #[macro_export]
306    #[doc(hidden)]
307    macro_rules! __if_wasm {
308        (($($true:tt)*) ($($false:tt)*)) => {
309            $($false)*
310        };
311    }
312
313    #[macro_export]
314    #[doc(hidden)]
315    #[allow(unknown_lints, edition_2024_expr_fragment_specifier)]
316    macro_rules! __in_section_crate {
317        ((@v=0 ; (source=$source:ident) ; (type = untyped) ; (path = $path:path) ; (name = $name:ident) ; (meta = $meta:tt) ; (item = $item:tt))) => {
318            $crate::__in_section_crate!(@untyped (($name)()), , $path, $meta $item);
319        };
320        ((@v=0 ; (source=$source:ident) ; (type = $section_type:ident) ; (path = $path:path) ; (name = $name:ident) ; (meta = $meta:tt) ; (item = $item:tt))) => {
321            $crate::__in_section_crate!(@typed[$section_type] (($name)()), , $path, $meta $item);
322        };
323        ((@v=0 ; (source=$source:ident) ; (type = untyped) ; (section = $section:tt) $(; (path = $path:path) ; (name = $name:ident))? ; (meta = $meta:tt) ; (item = $item:tt))) => {
324            $crate::__in_section_crate!(@untyped $section, , $($path)?, $meta $item);
325        };
326        ((@v=0 ; (source=$source:ident) ; (type = $section_type:ident) ; (section = $section:tt) $(; (path = $path:path) ; (name = $name:ident))? ; (meta = $meta:tt) ; (item = $item:tt))) => {
327            $crate::__in_section_crate!(@typed[$section_type] $section, , $($path)?, $meta $item);
328        };
329
330        // Untyped items are placed in the data or code section as-is.
331        (@untyped $section:tt, , $($path:path)?, ($($meta:tt)*) ($vis:vis fn $($rest:tt)*)) => {
332            $crate::__add_section_link_attribute!(
333                item code section $section
334                #[link_section = __]
335                $($meta)*
336                $vis fn $($rest)*
337            );
338            $(
339                const _: () = {
340                    $crate::Section::__validate(&$path);
341                };
342            )?
343        };
344        (@untyped $section:tt, , $($path:path)?, ($($meta:tt)*) ($($rest:tt)*)) => {
345            $crate::__add_section_link_attribute!(
346                item data section $section
347                #[link_section = __]
348                $($meta)*
349                $($rest)*
350            );
351            $(
352                const _: () = {
353                    $crate::Section::__validate(&$path);
354                };
355            )?
356        };
357
358        // Convert fn() with a body to a const item and a function pointer item.
359        (@typed[$section_type:ident] $section:tt, , $($path:path)?, ($($meta:tt)*) ($vis:vis fn $ident_fn:ident($($args:tt)*) $(-> $ret:ty)? { $($body:tt)* })) => {
360            $($meta)*
361            $vis fn $ident_fn($($args)*) $(-> $ret)? {
362                $crate::__in_section_crate!(@typed[$section_type] $section, , $($path)?, () (
363                    const _: fn($($args)*) $(-> $ret)? = $ident_fn;
364                ));
365
366                $($body)*
367            }
368        };
369
370        // If no path is provided, use the item type.
371        (@typed[$section_type:ident] $section:tt, , , $meta:tt ($vis:vis $const_or_static:ident $name:tt : $ty:ty = $($rest:tt)*)) => {
372            $crate::__in_section_crate!(@typed[$section_type] $section, , $crate::TypedSection::<$ty>, $meta (
373                $vis $const_or_static $name: $ty = $($rest)*
374            ));
375        };
376
377        (@type_select $path:path) => {
378            <$path as $crate::__support::SectionItemType>::Item
379        };
380
381        // static items
382        (@typed[typed] $section:tt, , $path:path, ($($meta:tt)*) ($vis:vis static $ident:ident : $ty:ty = $value:expr;)) => {
383            $crate::__if_wasm!(
384                (
385                    compile_error!("static items are not supported on WASM: use const items instead");
386                )
387                (
388                    $crate::__add_section_link_attribute!(
389                        item data section $section
390                        #[link_section = __]
391                        $($meta)*
392                        $vis static $ident: $crate::__in_section_crate!(@type_select $path) = const {
393                            const _: () = {
394                                let _: *const <$path as $crate::__support::SectionItemTyped<$ty>>::Item = ::core::ptr::null();
395                            };
396
397                            $value
398                        };
399                    );
400                )
401            );
402        };
403
404        // mutable const items live in SyncUnsafeCell
405        (@typed[mutable] $section:tt, , $path:path, ($($meta:tt)*) ($vis:vis const $ident:tt: $ty:ty = $value:expr;)) => {
406            $($meta)*
407            $vis const $ident: $ty = const {
408                type __InSecStoredTy = $crate::__in_section_crate!(@type_select $path);
409                const __LINK_SECTION_CONST_ITEM_VALUE: __InSecStoredTy = $value;
410
411                $crate::__register_wasm_item!(mutable, type=__InSecStoredTy, value=__LINK_SECTION_CONST_ITEM_VALUE, section=$section);
412
413                $crate::__if_wasm!(() (
414                    $crate::__add_section_link_attribute!(
415                        item data section $section
416                        #[link_section = __]
417                        static __LINK_SECTION_CONST_ITEM: $crate::__support::SyncUnsafeCell<__InSecStoredTy> = $crate::__support::SyncUnsafeCell::new(__LINK_SECTION_CONST_ITEM_VALUE);
418                    );
419                ));
420
421                __LINK_SECTION_CONST_ITEM_VALUE
422            };
423        };
424
425        (@typed[mutable] $($rest:tt)*) => {
426            compile_error!("Only const items are supported in mutable sections");
427        };
428
429        // movable static items expose a MovableRef and submit hidden value/backref records.
430        (@typed[movable] $section:tt, , $path:path, ($($meta:tt)*) ($vis:vis static $ident:ident: $ty:ty = $value:expr;)) => {
431            $($meta)*
432            $vis static $ident: $crate::MovableRef<$crate::__in_section_crate!(@type_select $path)> = const {
433                const __LINK_SECTION_CONST_ITEM_VALUE: __InSecStoredTy = $value;
434                type __InSecStoredTy = $crate::__in_section_crate!(@type_select $path);
435
436                $crate::__if_wasm!((
437                    {
438                        $crate::__register_wasm_item!(
439                            movable,
440                            type=__InSecStoredTy,
441                            value=__LINK_SECTION_CONST_ITEM_VALUE,
442                            slot=$crate::MovableRef::slot_ptr(&raw const $ident),
443                            section=$section
444                        );
445
446                        // Import the section info so the handle can lazily flatten.
447                        $crate::__import_section_info!(
448                            $crate::__support::wasm::LinkSectionMovableInfo,
449                            __LINK_SECTION_MOVABLE_INFO,
450                            $section
451                        );
452
453                        $crate::MovableRef::new($crate::__support::MovableRefStorage::new(::core::ptr::null(), &raw const __LINK_SECTION_MOVABLE_INFO))
454                    }
455                )(
456                    {
457                        $crate::__add_section_link_attribute!(
458                            item data section $section
459                            #[link_section = __]
460                            static __LINK_SECTION_CONST_ITEM: $crate::__support::SyncUnsafeCell<__InSecStoredTy> =
461                                $crate::__support::SyncUnsafeCell::new(__LINK_SECTION_CONST_ITEM_VALUE);
462                        );
463
464                        $crate::__add_section_link_attribute!(
465                            backref data section $section
466                            #[link_section = __]
467                            static __LINK_SECTION_MOVABLE_BACKREF: $crate::__support::SyncUnsafeCell<
468                                $crate::MovableBackref<__InSecStoredTy>
469                            > = $crate::__support::SyncUnsafeCell::new(
470                                $crate::MovableBackref::new(
471                                    $crate::MovableRef::slot_ptr(&raw const $ident),
472                                )
473                            );
474                        );
475
476                        $crate::MovableRef::new($crate::__support::MovableRefStorage::new(
477                            (&raw const __LINK_SECTION_CONST_ITEM)
478                                .cast::<__InSecStoredTy>(),
479                        ))
480                    }
481                ))
482            };
483        };
484
485        (@typed[movable] $($rest:tt)*) => {
486            compile_error!("Only static items are supported in movable sections");
487        };
488
489        // const items are the same across all other types
490        (@typed[$section_type:ident] $section:tt, , $path:path, ($($meta:tt)*) ($vis:vis const $ident:tt: $ty:ty = $value:expr;)) => {
491            $($meta)*
492            $vis const $ident: $ty = const {
493                type __InSecStoredTy = $crate::__in_section_crate!(@type_select $path);
494                const __LINK_SECTION_CONST_ITEM_VALUE: __InSecStoredTy = $value;
495
496                $crate::__if_wasm!((
497                    $crate::__register_wasm_item!($section_type, type=__InSecStoredTy, value=__LINK_SECTION_CONST_ITEM_VALUE, section=$section);
498                ) (
499                    $crate::__add_section_link_attribute!(
500                        item data section $section
501                        #[link_section = __]
502                        static __LINK_SECTION_CONST_ITEM: __InSecStoredTy = __LINK_SECTION_CONST_ITEM_VALUE;
503                    );
504                ));
505
506                __LINK_SECTION_CONST_ITEM_VALUE
507            };
508        };
509
510        (@typed[reference] $section:tt, , $path:path, ($($meta:tt)*) ($vis:vis static $ident:ident: $ty:ty = $value:expr;)) => {
511            $crate::__if_wasm!(
512                (
513                    $($meta)*
514                    $vis static $ident: $crate::reference::Ref<$crate::__in_section_crate!(@type_select $path)> = {
515                        type __InSecStoredTy = $crate::__in_section_crate!(@type_select $path);
516                        const __LINK_SECTION_CONST_ITEM_VALUE: __InSecStoredTy = $value;
517                        $crate::__register_wasm_item!(reference, type=__InSecStoredTy, value=__LINK_SECTION_CONST_ITEM_VALUE, ref=$ident, section=$section);
518                        // Import the section info so the handle can lazily flatten.
519                        $crate::__import_section_info!(
520                            $crate::__support::wasm::LinkSectionInfo,
521                            __LINK_SECTION_REF_INFO,
522                            $section
523                        );
524                        $crate::reference::Ref::new($crate::__support::RefStorage::new(&raw const __LINK_SECTION_REF_INFO))
525                    };
526                )
527                (
528                    // Layout-compatible with the value, so stored directly in the section.
529                    #[cfg(not(target_family="wasm"))]
530                    $crate::__add_section_link_attribute!(
531                        item data section $section
532                        #[link_section = __]
533                        $($meta)*
534                        $vis static $ident: $crate::reference::Ref<$crate::__in_section_crate!(@type_select $path)> = $crate::reference::Ref::new($crate::__support::RefStorage::new($value));
535                    );
536                )
537            );
538        };
539
540        ($($input:tt)*) => {
541            compile_error!(concat!("Unexpected input to __in_section_crate: ", stringify!($($input)*)));
542        };
543    }
544}
545
546/// Define a link section.
547///
548/// The definition site generates two items: a static section struct that is
549/// used to access the section, and a macro that is used to place items into the
550/// section. The macro is used by the [`in_section`] procedural macro.
551///
552/// # Attributes
553///
554/// - `no_macro`: Does not generate the submission macro at the definition site.
555///   This will require any associated [`in_section`] invocations to use the raw
556///   name of the section.
557/// - `aux(main = <name>)`: Specifies that this section is an auxiliary section, and
558///   that the section is named `<name>+<aux>`.
559///
560/// # Example
561/// ```rust
562/// use link_section::{in_section, section};
563///
564/// #[section(untyped)]
565/// pub static DATA_SECTION: link_section::Section;
566///
567/// #[in_section(DATA_SECTION)]
568/// pub fn data_function() {
569///     println!("data_function");
570/// }
571/// ```
572#[cfg(feature = "proc_macro")]
573pub use ::linktime_proc_macro::section;
574
575/// Place an item into a link section.
576///
577/// # Functions and typed sections
578///
579/// As a special case, since function declarations by themselves are not sized,
580/// functions in typed sections are split and stored as function pointers.
581///
582/// ## Raw items
583///
584/// This macro can place items into a section that is not normally visible to it
585/// by using `#[in_section(unsafe, type = typed|movable|..., name =
586/// SECTION_NAME, ...)`. Raw items are not validated at compile time, and must
587/// be validated by the author.
588#[cfg(feature = "proc_macro")]
589pub use ::linktime_proc_macro::in_section;