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