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