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.
197        ($definition:tt $prefix:tt $name:tt $suffix:tt $hash_length:literal $max_length:literal $valid_section_chars:literal) => {
198            $crate::__support::combine!(output=string input=(
199                $prefix
200                __SUBSTRING__(input=(
201                    __SUBSTRING__(input=(
202                        __TOIDENT__(input=(__RAW__(input=($name))))
203                    ) end=(__SUB__(a=$max_length b=$hash_length)))
204                    // Hash the location information for the full
205                    // definition and computed name.
206                    __LOCATIONHASH__(of=($definition $name) alphabet=[_0-9a-zA-Z])
207                ) length=$max_length)
208                $suffix
209            ))
210        };
211    }
212
213    #[cfg(feature = "proc_macro")]
214    pub use __hash_proc_macro as hash;
215
216    #[cfg(not(feature = "proc_macro"))]
217    pub use __hash_no_proc_macro as hash;
218
219    #[cfg(miri)]
220    #[doc(hidden)]
221    #[macro_export]
222    macro_rules! __address_of_symbol {
223        ($ref_or_item:ident $section:ident $type:ident $name:tt) => {
224            // Miri does not support any of these linker-defined extern statics
225            // see: https://github.com/rust-lang/miri/blob/master/src/shims/extern_static.rs#L15
226            ::core::ptr::null() as *const ()
227        };
228    }
229
230    #[cfg(not(miri))]
231    #[doc(hidden)]
232    #[macro_export]
233    macro_rules! __address_of_symbol {
234        ($ref_or_item:ident $section:ident $type:ident $name:tt) => {
235            {
236                // These are not valid items, but they are valid pointers.
237                // We cannot safely use them - only take pointers to them.
238                $crate::__add_linktime_attributes_to_static!(
239                    extern "C" {
240                        #[link_name = $crate::__support::section_name!(string $ref_or_item $section $type $name)]
241                        static __SYMBOL: u8;
242                    }
243                );
244                // TODO: black_box when hint is stable
245                // TODO: MSRV: we can use &raw const once we bump MSRV
246                // unsafe { &raw const __SYMBOL as *const () }
247                unsafe { ::core::ptr::addr_of!(__SYMBOL) as *const () }
248            }
249        }
250    }
251
252    #[doc(hidden)]
253    #[macro_export]
254    macro_rules! __add_section_link_attribute(
255        ($ref_or_item:ident $section:ident $type:ident $name:tt #[$attr:ident = __]
256            $(#[$meta:meta])*
257            $vis:vis static $($static:tt)*
258        ) => {
259            $crate::__add_linktime_attributes_to_static!(
260                #[$attr = $crate::__support::section_name!(string $ref_or_item $section $type $name)]
261                $(#[$meta])*
262                $vis static $($static)*
263            );
264        };
265        ($ref_or_item:ident $section:ident $type:ident $name:tt #[$attr:ident = __]
266            extern "C" {
267                $(#[$meta:meta])*
268                $vis:vis static $($static:tt)*
269            }
270        ) => {
271            $crate::__add_linktime_attributes_to_static!(
272                extern "C" {
273                    #[link_name = $crate::__support::section_name!(string $ref_or_item $section $type $name)]
274                    $(#[$meta])*
275                    $vis static $($static)*
276                }
277            );
278        };
279        ($ref_or_item:ident $section:ident $type:ident $name:tt #[$attr:ident = __]
280            $($item:tt)*) => {
281            $crate::__add_linktime_attributes_to_static!(
282                #[$attr = $crate::__support::section_name!(string $ref_or_item $section $type $name)]
283                $($item)*
284            );
285        };
286    );
287
288    #[cfg(target_family = "wasm")]
289    #[macro_export]
290    #[doc(hidden)]
291    macro_rules! __if_wasm {
292        (($($true:tt)*) ($($false:tt)*)) => {
293            $($true)*
294        };
295    }
296
297    #[cfg(not(target_family = "wasm"))]
298    #[macro_export]
299    #[doc(hidden)]
300    macro_rules! __if_wasm {
301        (($($true:tt)*) ($($false:tt)*)) => {
302            $($false)*
303        };
304    }
305
306    #[macro_export]
307    #[doc(hidden)]
308    #[allow(unknown_lints, edition_2024_expr_fragment_specifier)]
309    macro_rules! __in_section_crate {
310        ((@v=0 ; (source=$source:ident) ; (type = untyped) ; (path = $path:path) ; (name = $name:ident) ; (meta = $meta:tt) ; (item = $item:tt))) => {
311            $crate::__in_section_crate!(@untyped (($name)()), , $path, $meta $item);
312        };
313        ((@v=0 ; (source=$source:ident) ; (type = $section_type:ident) ; (path = $path:path) ; (name = $name:ident) ; (meta = $meta:tt) ; (item = $item:tt))) => {
314            $crate::__in_section_crate!(@typed[$section_type] (($name)()), , $path, $meta $item);
315        };
316        ((@v=0 ; (source=$source:ident) ; (type = untyped) ; (section = $section:tt) $(; (path = $path:path) ; (name = $name:ident))? ; (meta = $meta:tt) ; (item = $item:tt))) => {
317            $crate::__in_section_crate!(@untyped $section, , $($path)?, $meta $item);
318        };
319        ((@v=0 ; (source=$source:ident) ; (type = $section_type:ident) ; (section = $section:tt) $(; (path = $path:path) ; (name = $name:ident))? ; (meta = $meta:tt) ; (item = $item:tt))) => {
320            $crate::__in_section_crate!(@typed[$section_type] $section, , $($path)?, $meta $item);
321        };
322
323        // Untyped items are placed in the data or code section as-is.
324        (@untyped $section:tt, , $($path:path)?, ($($meta:tt)*) ($vis:vis fn $($rest:tt)*)) => {
325            $crate::__add_section_link_attribute!(
326                item code section $section
327                #[link_section = __]
328                $($meta)*
329                $vis fn $($rest)*
330            );
331            $(
332                const _: () = {
333                    $crate::Section::__validate(&$path);
334                };
335            )?
336        };
337        (@untyped $section:tt, , $($path:path)?, ($($meta:tt)*) ($($rest:tt)*)) => {
338            $crate::__add_section_link_attribute!(
339                item data section $section
340                #[link_section = __]
341                $($meta)*
342                $($rest)*
343            );
344            $(
345                const _: () = {
346                    $crate::Section::__validate(&$path);
347                };
348            )?
349        };
350
351        // Convert fn() with a body to a const item and a function pointer item.
352        (@typed[$section_type:ident] $section:tt, , $($path:path)?, ($($meta:tt)*) ($vis:vis fn $ident_fn:ident($($args:tt)*) $(-> $ret:ty)? { $($body:tt)* })) => {
353            $($meta)*
354            $vis fn $ident_fn($($args)*) $(-> $ret)? {
355                $crate::__in_section_crate!(@typed[$section_type] $section, , $($path)?, () (
356                    const _: fn($($args)*) $(-> $ret)? = $ident_fn;
357                ));
358
359                $($body)*
360            }
361        };
362
363        // If no path is provided, use the item type.
364        (@typed[$section_type:ident] $section:tt, , , $meta:tt ($vis:vis $const_or_static:ident $name:tt : $ty:ty = $($rest:tt)*)) => {
365            $crate::__in_section_crate!(@typed[$section_type] $section, , $crate::TypedSection::<$ty>, $meta (
366                $vis $const_or_static $name: $ty = $($rest)*
367            ));
368        };
369
370        (@type_select $path:path) => {
371            <$path as $crate::__support::SectionItemType>::Item
372        };
373
374        // static items
375        (@typed[typed] $section:tt, , $path:path, ($($meta:tt)*) ($vis:vis static $ident:ident : $ty:ty = $value:expr;)) => {
376            $crate::__if_wasm!(
377                (
378                    compile_error!("static items are not supported on WASM: use const items instead");
379                )
380                (
381                    $crate::__add_section_link_attribute!(
382                        item data section $section
383                        #[link_section = __]
384                        $($meta)*
385                        $vis static $ident: $crate::__in_section_crate!(@type_select $path) = const {
386                            const _: () = {
387                                let _: *const <$path as $crate::__support::SectionItemTyped<$ty>>::Item = ::core::ptr::null();
388                            };
389
390                            $value
391                        };
392                    );
393                )
394            );
395        };
396
397        // mutable const items live in SyncUnsafeCell
398        (@typed[mutable] $section:tt, , $path:path, ($($meta:tt)*) ($vis:vis const $ident:tt: $ty:ty = $value:expr;)) => {
399            $($meta)*
400            $vis const $ident: $ty = const {
401                type __InSecStoredTy = $crate::__in_section_crate!(@type_select $path);
402                const __LINK_SECTION_CONST_ITEM_VALUE: __InSecStoredTy = $value;
403
404                $crate::__register_wasm_item!(mutable, value=__LINK_SECTION_CONST_ITEM_VALUE, section=$section);
405
406                $crate::__if_wasm!(() (
407                    $crate::__add_section_link_attribute!(
408                        item data section $section
409                        #[link_section = __]
410                        static __LINK_SECTION_CONST_ITEM: $crate::__support::SyncUnsafeCell<__InSecStoredTy> = $crate::__support::SyncUnsafeCell::new(__LINK_SECTION_CONST_ITEM_VALUE);
411                    );
412                ));
413
414                __LINK_SECTION_CONST_ITEM_VALUE
415            };
416        };
417
418        (@typed[mutable] $($rest:tt)*) => {
419            compile_error!("Only const items are supported in mutable sections");
420        };
421
422        // movable static items expose a MovableRef and submit hidden value/backref records.
423        (@typed[movable] $section:tt, , $path:path, ($($meta:tt)*) ($vis:vis static $ident:ident: $ty:ty = $value:expr;)) => {
424            $($meta)*
425            $vis static $ident: $crate::MovableRef<$crate::__in_section_crate!(@type_select $path)> = const {
426                const __LINK_SECTION_CONST_ITEM_VALUE: __InSecStoredTy = $value;
427                type __InSecStoredTy = $crate::__in_section_crate!(@type_select $path);
428
429                $crate::__if_wasm!((
430                    {
431                        $crate::__register_wasm_item!(
432                            movable,
433                            value=__LINK_SECTION_CONST_ITEM_VALUE,
434                            slot=$crate::MovableRef::slot_ptr(&raw const $ident),
435                            section=$section
436                        );
437
438                        $crate::MovableRef::new(::core::ptr::null())
439                    }
440                )(
441                    {
442                        $crate::__add_section_link_attribute!(
443                            item data section $section
444                            #[link_section = __]
445                            static __LINK_SECTION_CONST_ITEM: $crate::__support::SyncUnsafeCell<__InSecStoredTy> =
446                                $crate::__support::SyncUnsafeCell::new(__LINK_SECTION_CONST_ITEM_VALUE);
447                        );
448
449                        $crate::__add_section_link_attribute!(
450                            backref data section $section
451                            #[link_section = __]
452                            static __LINK_SECTION_MOVABLE_BACKREF: $crate::__support::SyncUnsafeCell<
453                                $crate::MovableBackref<__InSecStoredTy>
454                            > = $crate::__support::SyncUnsafeCell::new(
455                                $crate::MovableBackref::new(
456                                    $crate::MovableRef::slot_ptr(&raw const $ident),
457                                )
458                            );
459                        );
460
461                        $crate::MovableRef::new(
462                            (&raw const __LINK_SECTION_CONST_ITEM)
463                                .cast::<__InSecStoredTy>(),
464                        )
465                    }
466                ))
467            };
468        };
469
470        (@typed[movable] $($rest:tt)*) => {
471            compile_error!("Only static items are supported in movable sections");
472        };
473
474        // const items are the same across all other types
475        (@typed[$section_type:ident] $section:tt, , $path:path, ($($meta:tt)*) ($vis:vis const $ident:tt: $ty:ty = $value:expr;)) => {
476            $($meta)*
477            $vis const $ident: $ty = const {
478                type __InSecStoredTy = $crate::__in_section_crate!(@type_select $path);
479                const __LINK_SECTION_CONST_ITEM_VALUE: __InSecStoredTy = $value;
480
481                $crate::__if_wasm!((
482                    $crate::__register_wasm_item!($section_type, value=__LINK_SECTION_CONST_ITEM_VALUE, section=$section);
483                ) (
484                    $crate::__add_section_link_attribute!(
485                        item data section $section
486                        #[link_section = __]
487                        static __LINK_SECTION_CONST_ITEM: __InSecStoredTy = __LINK_SECTION_CONST_ITEM_VALUE;
488                    );
489                ));
490
491                __LINK_SECTION_CONST_ITEM_VALUE
492            };
493        };
494
495        (@typed[reference] $section:tt, , $path:path, ($($meta:tt)*) ($vis:vis static $ident:ident: $ty:ty = $value:expr;)) => {
496            $crate::__if_wasm!(
497                (
498                    $($meta)*
499                    $vis static $ident: $crate::reference::Ref<$crate::__in_section_crate!(@type_select $path)> = {
500                        type __InSecStoredTy = $crate::__in_section_crate!(@type_select $path);
501                        const __LINK_SECTION_CONST_ITEM_VALUE: __InSecStoredTy = $value;
502                        $crate::__register_wasm_item!(reference, value=__LINK_SECTION_CONST_ITEM_VALUE, ref=$ident, section=$section);
503                        $crate::reference::Ref::new()
504                    };
505                )
506                (
507                    // On non-WASM platforms, we can store the value directly (repr(transparent) allows this).
508                    #[cfg(not(target_family="wasm"))]
509                    $crate::__add_section_link_attribute!(
510                        item data section $section
511                        #[link_section = __]
512                        $($meta)*
513                        $vis static $ident: $crate::reference::Ref<$crate::__in_section_crate!(@type_select $path)> = $crate::reference::Ref::new($value);
514                    );
515                )
516            );
517        };
518
519        ($($input:tt)*) => {
520            compile_error!(concat!("Unexpected input to __in_section_crate: ", stringify!($($input)*)));
521        };
522    }
523}
524
525/// Define a link section.
526///
527/// The definition site generates two items: a static section struct that is
528/// used to access the section, and a macro that is used to place items into the
529/// section. The macro is used by the [`in_section`] procedural macro.
530///
531/// # Attributes
532///
533/// - `no_macro`: Does not generate the submission macro at the definition site.
534///   This will require any associated [`in_section`] invocations to use the raw
535///   name of the section.
536/// - `aux(main = <name>)`: Specifies that this section is an auxiliary section, and
537///   that the section is named `<name>+<aux>`.
538///
539/// # Example
540/// ```rust
541/// use link_section::{in_section, section};
542///
543/// #[section(untyped)]
544/// pub static DATA_SECTION: link_section::Section;
545///
546/// #[in_section(DATA_SECTION)]
547/// pub fn data_function() {
548///     println!("data_function");
549/// }
550/// ```
551#[cfg(feature = "proc_macro")]
552pub use ::linktime_proc_macro::section;
553
554/// Place an item into a link section.
555///
556/// # Functions and typed sections
557///
558/// As a special case, since function declarations by themselves are not sized,
559/// functions in typed sections are split and stored as function pointers.
560///
561/// ## Raw items
562///
563/// This macro can place items into a section that is not normally visible to it
564/// by using `#[in_section(unsafe, type = typed|movable|..., name =
565/// SECTION_NAME, ...)`. Raw items are not validated at compile time, and must
566/// be validated by the author.
567#[cfg(feature = "proc_macro")]
568pub use ::linktime_proc_macro::in_section;