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
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    /// Define a custom macro name for the submission macro. Note that this is
49    /// required when not using the `proc_macro` feature and using `aux`.
50    macro_unique_name {
51        attr: [(macro_unique_name = $macro_unique_name_str:ident) => (($macro_unique_name_str))];
52        example: "macro_unique_name = my_unique_name_1234";
53    };
54    /// Disable submission macro generation at the definition site.
55    no_macro {
56        attr: [(no_macro) => (no_macro)];
57    };
58    /// Crate feature `proc_macro` (enables the `#[section]` attribute shim).
59    proc_macro {
60        feature: "proc_macro";
61    };
62    /// The type of the section.
63    type {
64        attr: [
65            (type = $section_type:ident) => ($section_type)
66        ];
67        example: "untyped | typed | mutable | movable | reference";
68        validate: [(untyped), (typed), (mutable), (movable), (reference)];
69    };
70);
71
72#[cfg(doc)]
73__generate_docs!(__section_features);
74
75__declare_features!(
76    in_section: __in_section_features;
77
78    @default: section;
79
80    section {
81        attr: [(section = $($section_path:tt)*) => (($($section_path)*))];
82        example: "[section = ] ::path::to::SECTION";
83        validate: [(($section_path:path))];
84    };
85    aux {
86        attr: [(aux(main = $aux_str:ident)) => ($aux_str)];
87        example: "aux(main = MAIN_SECTION)";
88    };
89    name {
90        attr: [(name = $name_str:ident) => ($name_str)];
91        example: "name = SECTION";
92    };
93    section_type {
94        attr: [(type = $section_type_name:ident) => ($section_type_name)];
95        example: "type = untyped | typed | mutable | movable | reference";
96        validate: [(untyped), (typed), (mutable), (movable), (reference)];
97    };
98    unsafe {
99        attr: [(unsafe) => (unsafe)];
100    };
101);
102
103#[cfg(target_family = "wasm")]
104extern crate alloc;
105
106/// Declarative forms of the `#[section]` and `#[in_section(...)]` macros.
107///
108/// The declarative forms wrap and parse a proc_macro-like syntax like so, and
109/// are identical in expansion to the undecorated procedural macros. The
110/// declarative forms support the same attribute parameters as the procedural
111/// macros.
112pub mod declarative {
113    pub use crate::__in_section_parse as in_section;
114    pub use crate::__section_parse as section;
115}
116
117#[doc(hidden)]
118pub mod __support {
119    pub use crate::__add_section_link_attribute as add_section_link_attribute;
120    pub use crate::__in_section_crate as in_section_crate;
121    pub use crate::__in_section_parse as in_section_parse;
122    pub use crate::__section_parse as section_parse;
123
124    pub use crate::sections::IsUntypedSection;
125    pub use crate::{item::*, platform::*};
126
127    #[cfg(feature = "proc_macro")]
128    pub use linktime_proc_macro::hash;
129    #[cfg(feature = "proc_macro")]
130    pub use linktime_proc_macro::ident_concat;
131
132    #[doc(hidden)]
133    #[macro_export]
134    macro_rules! __hash_no_proc_macro {
135        ((__) (($($__prefix:literal $(,)?)*)) ($($name:tt)*) (($($__suffix:literal $(,)?)*)) $__hash_length:literal $__max_length:literal $__valid_section_chars:literal) => {
136            concat!($($__prefix,)* $(stringify!($name)),* $(,$__suffix)*);
137        };
138    }
139    #[cfg(not(feature = "proc_macro"))]
140    pub use __hash_no_proc_macro as hash;
141
142    #[cfg(miri)]
143    #[doc(hidden)]
144    #[macro_export]
145    macro_rules! __address_of_symbol {
146        ($ref_or_item:ident $section:ident $type:ident $name:ident $($aux:ident)?) => {
147            // Miri does not support any of these linker-defined extern statics
148            // see: https://github.com/rust-lang/miri/blob/master/src/shims/extern_static.rs#L15
149            ::core::ptr::null() as *const ()
150        };
151    }
152
153    #[cfg(not(miri))]
154    #[doc(hidden)]
155    #[macro_export]
156    macro_rules! __address_of_symbol {
157        ($ref_or_item:ident $section:ident $type:ident $name:ident $($aux:ident)?) => {
158            {
159                // These are not valid items, but they are valid pointers.
160                // We cannot safely use them - only take pointers to them.
161                $crate::__add_linktime_attributes_to_static!(
162                    extern "C" {
163                        #[link_name = $crate::__support::section_name!(string $ref_or_item $section $type $name $($aux)?)]
164                        static __SYMBOL: u8;
165                    }
166                );
167                // TODO: black_box when hint is stable
168                // TODO: MSRV: we can use &raw const once we bump MSRV
169                // unsafe { &raw const __SYMBOL as *const () }
170                unsafe { ::core::ptr::addr_of!(__SYMBOL) as *const () }
171            }
172        };
173    }
174
175    #[doc(hidden)]
176    #[macro_export]
177    macro_rules! __add_section_link_attribute(
178        ($ref_or_item:ident $section:ident $type:ident $name:ident $($aux:ident)? #[$attr:ident = __]
179            $(#[$meta:meta])*
180            $vis:vis static $($static:tt)*
181        ) => {
182            $crate::__add_linktime_attributes_to_static!(
183                #[$attr = $crate::__support::section_name!(string $ref_or_item $section $type $name $($aux)?)]
184                $(#[$meta])*
185                $vis static $($static)*
186            );
187        };
188        ($ref_or_item:ident $section:ident $type:ident $name:ident $($aux:ident)? #[$attr:ident = __]
189            extern "C" {
190                $(#[$meta:meta])*
191                $vis:vis static $($static:tt)*
192            }
193        ) => {
194            $crate::__add_linktime_attributes_to_static!(
195                extern "C" {
196                    #[link_name = $crate::__support::section_name!(string $ref_or_item $section $type $name $($aux)?)]
197                    $(#[$meta])*
198                    $vis static $($static)*
199                }
200            );
201        };
202        ($ref_or_item:ident $section:ident $type:ident $name:ident $($aux:ident)? #[$attr:ident = __]
203            $($item:tt)*) => {
204            $crate::__add_linktime_attributes_to_static!(
205                #[$attr = $crate::__support::section_name!(string $ref_or_item $section $type $name $($aux)?)]
206                $($item)*
207            );
208        };
209    );
210
211    // Without the proc macro, only name/type supported (no `aux`).
212    #[doc(hidden)]
213    #[macro_export]
214    macro_rules! __declare_macro {
215        ($vis:vis $ident:ident $generic_macro:ident) => {
216            /// Internal macro for parsing the section. This is exported with
217            /// the same name as the type below.
218            #[doc(hidden)]
219            $vis use $crate::$generic_macro as $ident;
220        };
221    }
222
223    #[macro_export]
224    #[doc(hidden)]
225    macro_rules! __in_section_helper_macro_generic {
226        (($($args:tt)*)) => { $crate::__support::in_section_crate!((@v=0 ; (source=section) ; (type=typed) ; $($args)*)); }
227    }
228
229    #[macro_export]
230    #[doc(hidden)]
231    macro_rules! __in_section_helper_macro_generic_mutable {
232        (($($args:tt)*)) => { $crate::__support::in_section_crate!((@v=0 ; (source=section) ; (type=mutable) ; $($args)*)); }
233    }
234
235    #[macro_export]
236    #[doc(hidden)]
237    macro_rules! __in_section_helper_macro_generic_movable {
238        (($($args:tt)*)) => { $crate::__support::in_section_crate!((@v=0 ; (source=section) ; (type=movable) ; $($args)*)); }
239    }
240
241    #[macro_export]
242    #[doc(hidden)]
243    macro_rules! __in_section_helper_macro_generic_reference {
244        (($($args:tt)*)) => { $crate::__support::in_section_crate!((@v=0 ; (source=section) ; (type=reference) ; $($args)*)); }
245    }
246
247    #[macro_export]
248    #[doc(hidden)]
249    macro_rules! __in_section_helper_macro_no_generic {
250        (($($args:tt)*)) => { $crate::__support::in_section_crate!((@v=0 ; (source=section) ; (type=untyped) ; $($args)*)); }
251    }
252
253    #[macro_export]
254    #[doc(hidden)]
255    #[allow(unknown_lints, edition_2024_expr_fragment_specifier)]
256    macro_rules! __in_section_crate {
257        ((@v=0 ; (source=$source:ident) ; (type = untyped) $(; (aux = $aux:ident))? ; (section = $section:tt) $(; (path = $path:path))? ; (meta = $meta:tt) ; (item = $item:tt))) => {
258            $crate::__in_section_crate!(@untyped $section, $($aux)?, $($path)?, $meta $item);
259        };
260        ((@v=0 ; (source=$source:ident) ; (type = $section_type:ident) $(; (aux = $aux:ident))? ; (section = $section:tt) $(; (path = $path:path))? ; (meta = $meta:tt) ; (item = $item:tt))) => {
261            $crate::__in_section_crate!(@typed[$section_type] $section, $($aux)?, $($path)?, $meta $item);
262        };
263
264        // Untyped items are placed in the data or code section as-is.
265        (@untyped $section:tt, $($aux:ident)?, $($path:path)?, ($($meta:tt)*) ($vis:vis fn $($rest:tt)*)) => {
266            $crate::__add_section_link_attribute!(
267                item code section $section $($aux)?
268                #[link_section = __]
269                $($meta)*
270                $vis fn $($rest)*
271            );
272            $(
273                const _: () = {
274                    $crate::Section::__validate(&$path);
275                };
276            )?
277        };
278        (@untyped $section:tt, $($aux:ident)?, $($path:path)?, ($($meta:tt)*) ($($rest:tt)*)) => {
279            $crate::__add_section_link_attribute!(
280                item data section $section $($aux)?
281                #[link_section = __]
282                $($meta)*
283                $($rest)*
284            );
285            $(
286                const _: () = {
287                    $crate::Section::__validate(&$path);
288                };
289            )?
290        };
291
292        // Convert fn() with a body to a const item and a function pointer item.
293        (@typed[$section_type:ident] $section:tt, $($aux:ident)?, $($path:path)?, ($($meta:tt)*) ($vis:vis fn $ident_fn:ident($($args:tt)*) $(-> $ret:ty)? { $($body:tt)* })) => {
294            $($meta)*
295            $vis fn $ident_fn($($args)*) $(-> $ret)? {
296                $crate::__in_section_crate!(@typed[$section_type] $section, $($aux)?, $($path)?, () (
297                    const _: fn($($args)*) $(-> $ret)? = $ident_fn;
298                ));
299
300                $($body)*
301            }
302        };
303
304        // If no path is provided, use the item type.
305        (@typed[$section_type:ident] $section:tt, $($aux:ident)?, , $meta:tt ($vis:vis $const_or_static:ident $name:tt : $ty:ty = $($rest:tt)*)) => {
306            $crate::__in_section_crate!(@typed[$section_type] $section, $($aux)?, $crate::TypedSection::<$ty>, $meta (
307                $vis $const_or_static $name: $ty = $($rest)*
308            ));
309        };
310
311        (@type_select $path:path) => {
312            <$path as $crate::__support::SectionItemType>::Item
313        };
314
315        // static items
316        (@typed[typed] $section:tt, $($aux:ident)?, $path:path, ($($meta:tt)*) ($vis:vis static $ident:ident : $ty:ty = $value:expr;)) => {
317            #[cfg(not(target_family = "wasm"))]
318            $crate::__add_section_link_attribute!(
319                item data section $section $($aux)?
320                #[link_section = __]
321                $($meta)*
322                $vis static $ident: $crate::__in_section_crate!(@type_select $path) = const {
323                    const _: () = {
324                        let _: *const <$path as $crate::__support::SectionItemTyped<$ty>>::Item = ::core::ptr::null();
325                    };
326
327                    $value
328                };
329            );
330
331            #[cfg(target_family = "wasm")]
332            compile_error!("static items are not supported on WASM: use const items instead");
333        };
334
335        // mutable const items live in SyncUnsafeCell
336        (@typed[mutable] $section:tt, $($aux:ident)?, $path:path, ($($meta:tt)*) ($vis:vis const $ident:tt: $ty:ty = $value:expr;)) => {
337            $($meta)*
338            $vis const $ident: $ty = const {
339                type __InSecStoredTy = $crate::__in_section_crate!(@type_select $path);
340                const __LINK_SECTION_CONST_ITEM_VALUE: __InSecStoredTy = $value;
341
342                $crate::__register_wasm_item!(mutable, value=__LINK_SECTION_CONST_ITEM_VALUE, section=$section $($aux)?);
343
344                #[cfg(not(target_family = "wasm"))]
345                $crate::__add_section_link_attribute!(
346                    item data section $section $($aux)?
347                    #[link_section = __]
348                    static __LINK_SECTION_CONST_ITEM: $crate::__support::SyncUnsafeCell<__InSecStoredTy> = $crate::__support::SyncUnsafeCell::new(__LINK_SECTION_CONST_ITEM_VALUE);
349                );
350
351                __LINK_SECTION_CONST_ITEM_VALUE
352            };
353        };
354
355        (@typed[mutable] $($rest:tt)*) => {
356            compile_error!("Only const items are supported in mutable sections");
357        };
358
359        // movable static items expose a MovableRef and submit hidden value/backref records.
360        (@typed[movable] $section:tt, $($aux:ident)?, $path:path, ($($meta:tt)*) ($vis:vis static $ident:ident: $ty:ty = $value:expr;)) => {
361            $($meta)*
362            $vis static $ident: $crate::MovableRef<$crate::__in_section_crate!(@type_select $path)> = const {
363                const __LINK_SECTION_CONST_ITEM_VALUE: __InSecStoredTy = $value;
364                type __InSecStoredTy = $crate::__in_section_crate!(@type_select $path);
365                #[cfg(not(target_family = "wasm"))]
366                {
367                    $crate::__add_section_link_attribute!(
368                        item data section $section $($aux)?
369                        #[link_section = __]
370                        static __LINK_SECTION_CONST_ITEM: $crate::__support::SyncUnsafeCell<__InSecStoredTy> =
371                            $crate::__support::SyncUnsafeCell::new(__LINK_SECTION_CONST_ITEM_VALUE);
372                    );
373
374                    $crate::__add_section_link_attribute!(
375                        backref data section $section $($aux)?
376                        #[link_section = __]
377                        static __LINK_SECTION_MOVABLE_BACKREF: $crate::__support::SyncUnsafeCell<
378                            $crate::MovableBackref<__InSecStoredTy>
379                        > = $crate::__support::SyncUnsafeCell::new(
380                            $crate::MovableBackref::new(
381                                $crate::MovableRef::slot_ptr(&raw const $ident),
382                            )
383                        );
384                    );
385
386                    $crate::MovableRef::new(
387                        (&raw const __LINK_SECTION_CONST_ITEM)
388                            .cast::<__InSecStoredTy>(),
389                    )
390                }
391
392                #[cfg(target_family = "wasm")]
393                {
394                    $crate::__register_wasm_item!(
395                        movable,
396                        value=__LINK_SECTION_CONST_ITEM_VALUE,
397                        slot=$crate::MovableRef::slot_ptr(&raw const $ident),
398                        section=$section $($aux)?
399                    );
400
401                    $crate::MovableRef::new(::core::ptr::null())
402                }
403            };
404        };
405
406        (@typed[movable] $($rest:tt)*) => {
407            compile_error!("Only static items are supported in movable sections");
408        };
409
410        // const items are the same across all other types
411        (@typed[$section_type:ident] $section:tt, $($aux:ident)?, $path:path, ($($meta:tt)*) ($vis:vis const $ident:tt: $ty:ty = $value:expr;)) => {
412            $($meta)*
413            $vis const $ident: $ty = const {
414                type __InSecStoredTy = $crate::__in_section_crate!(@type_select $path);
415                const __LINK_SECTION_CONST_ITEM_VALUE: __InSecStoredTy = $value;
416
417                $crate::__register_wasm_item!($section_type, value=__LINK_SECTION_CONST_ITEM_VALUE, section=$section $($aux)?);
418
419                #[cfg(not(target_family = "wasm"))]
420                $crate::__add_section_link_attribute!(
421                    item data section $section $($aux)?
422                    #[link_section = __]
423                    static __LINK_SECTION_CONST_ITEM: __InSecStoredTy = __LINK_SECTION_CONST_ITEM_VALUE;
424                );
425
426                __LINK_SECTION_CONST_ITEM_VALUE
427            };
428        };
429
430        (@typed[reference] $section:tt, $($aux:ident)?, $path:path, ($($meta:tt)*) ($vis:vis static $ident:ident: $ty:ty = $value:expr;)) => {
431            #[cfg(target_family="wasm")]
432            $($meta)*
433            $vis static $ident: $crate::reference::Ref<$crate::__in_section_crate!(@type_select $path)> = {
434                type __InSecStoredTy = $crate::__in_section_crate!(@type_select $path);
435                const __LINK_SECTION_CONST_ITEM_VALUE: __InSecStoredTy = $value;
436                $crate::__register_wasm_item!(reference, value=__LINK_SECTION_CONST_ITEM_VALUE, ref=$ident, section=$section $($aux)?);
437                $crate::reference::Ref::new()
438            };
439
440            // On non-WASM platforms, we can store the value directly (repr(transparent) allows this).
441            #[cfg(not(target_family="wasm"))]
442            $crate::__add_section_link_attribute!(
443                item data section $section $($aux)?
444                #[link_section = __]
445                $($meta)*
446                $vis static $ident: $crate::reference::Ref<$crate::__in_section_crate!(@type_select $path)> = $crate::reference::Ref::new($value);
447            );
448        };
449
450        ($($input:tt)*) => {
451            compile_error!(concat!("Unexpected input to __in_section_crate: ", stringify!($($input)*)));
452        };
453    }
454}
455
456/// Define a link section.
457///
458/// The definition site generates two items: a static section struct that is
459/// used to access the section, and a macro that is used to place items into the
460/// section. The macro is used by the [`in_section`] procedural macro.
461///
462/// # Attributes
463///
464/// - `no_macro`: Does not generate the submission macro at the definition site.
465///   This will require any associated [`in_section`] invocations to use the raw
466///   name of the section.
467/// - `aux(main = <name>)`: Specifies that this section is an auxiliary section, and
468///   that the section is named `<name>+<aux>`.
469///
470/// # Example
471/// ```rust
472/// use link_section::{in_section, section};
473///
474/// #[section(untyped)]
475/// pub static DATA_SECTION: link_section::Section;
476///
477/// #[in_section(DATA_SECTION)]
478/// pub fn data_function() {
479///     println!("data_function");
480/// }
481/// ```
482#[cfg(feature = "proc_macro")]
483pub use ::linktime_proc_macro::section;
484
485/// Place an item into a link section.
486///
487/// # Functions and typed sections
488///
489/// As a special case, since function declarations by themselves are not sized,
490/// functions in typed sections are split and stored as function pointers.
491///
492/// ## Raw items
493///
494/// This macro can place items into a section that is not normally visible to it
495/// by using `#[in_section(unsafe, type = typed|movable|..., name =
496/// SECTION_NAME, ...)`. Raw items are not validated at compile time, and must
497/// be validated by the author.
498#[cfg(feature = "proc_macro")]
499pub use ::linktime_proc_macro::in_section;