20 releases (7 breaking)
| new 0.16.1 | May 11, 2026 |
|---|---|
| 0.15.0 | May 6, 2026 |
| 0.0.1 | Mar 27, 2026 |
#242 in Procedural macros
353,456 downloads per month
Used in 2 crates
59KB
1K
SLoC
The crate is part of the linktime project.
| crate | docs | version |
|---|---|---|
linktime |
||
ctor |
||
dtor |
||
link-section |
link-section
A crate for defining link sections in Rust.
Sections are defined using the #[section] macro. This creates an associated
data and text section, and items decorated with the #[in_section] macro
are placed into the associated section.
Platform Support
| Platform | Support |
|---|---|
| Linux | ✅ Supported, uses orphan section handling (§1) |
| *BSD | ✅ Supported, uses orphan section handling (§1) |
| macOS | ✅ Fully supported |
| Windows | ✅ Fully supported |
| WASM | ✅ Fully supported (§2) (§3) |
| AIX | ✅ Supported (§4) |
| Other LLVM/GCC platforms | ✅ Supported, uses orphan section handling (§1) |
(§1) Orphan section handling is a feature of the linker that allows sections to be defined without a pre-defined name.
(§2) WASM requires const items, and uses ctor-like initialization to copy
data to a contiguous section. To access link-section slices in WASM in #[ctor]
functions, make sure to use at least #[ctor(priority = 1)].
(§3) Host environment support (by calling the exported register_link_section
function) is required to register each section with the runtime.
(§4) AIX requires -C link-arg=-bdbg:namedsects:ss which enables functionality
similar to LLVM/GCC's orphan section handling.
Platform Details
Each platform has a slightly different implementation of section control.
Linux and other LLVM/GCC platforms
- Has start/end symbols: ✅ (C-compatible names only)
- Supports linker sorting: ❌
On Linux and other LLVM/GCC platforms, the linker supports orphan sections,
which allow sections to be defined without a pre-defined name. These sections
are emitted as if they were r/w .data. For sections with C-compatible names,
the linker will emit start/end symbols for the section.
Orphan sections are not sorted via numeric suffix (e.g.: SECTION.1,
SECTION.2, etc.) with the default linker script.
macOS
- Has start/end symbols: ✅
- Supports linker sorting: ❌
On macOS, sections are configured via __DATA or __TEXT prefix and option
suffixes (regular, no_dead_strip, etc.). The linker emits start and stop
symbols, but Rust requires a (somewhat-stable) \x01 prefix to avoid mangling
the section name. macOS does not support ordering in the linker.
Windows
- Has start/end symbols: ❌
- Supports linker sorting: ✅
On Windows, the linker does not emit start/end symbols, but all sections with a common prefix are automatically sorted by suffix, allowing us to use suffixes to control placement of start/stop symbols that we emit.
See this blog post and this blog post for more details about the alphabetical sorting rule.
WASM
- Has start/end symbols: ❌
- Supports linker sorting: ❌
On WASM platforms, Rust emits data into custom sections which do not support ordering, and are stored out-of-band. The host environment is responsible for registering this out-of-band section with this library as this data is not accessible by the WASM runtime.
Normally, WASM does not support placing arbitrary data in link sections - only
non-pointer data is supported. However, the WASM support uses const items and
pre-main construction functions to copy each entry into a contiguous section
allocated at startup. The number of items in a link-section is computed by
generating a custom data section containing one byte per item.
The WASM support expects a function in the module's environment with the
following signature and functionality. The wasm import only passes the four
usize / pointer parameters; the embedder should close over
WebAssembly.Module and WebAssembly.Memory from compile/instantiate when
installing the import.
/**
* Support function for `link-section` crate.
*/
export function readCustomSection(
wasmModule: WebAssembly.Module,
wasmInstance: WebAssembly.Instance,
namePtr: number,
nameLength: number,
targetPtr: number,
targetLength: number,
): number {
const memory = wasmInstance.exports.memory as WebAssembly.Memory;
const nameBytes = new Uint8Array(memory.buffer, namePtr, nameLength);
const sectionName = new TextDecoder().decode(nameBytes);
const sections = WebAssembly.Module.customSections(wasmModule, sectionName);
if (sections.length === 0) {
return 0;
}
const section = sections[0];
const need = section.byteLength;
if (targetLength < need) {
return need;
}
new Uint8Array(memory.buffer, targetPtr, need).set(new Uint8Array(section));
return need;
}
AIX
- Has start/end symbols: ✅
- Supports linker sorting: ❌
AIX maps Rust's #[link_section] to csects (Control Sections), which act like
subsections of the larger .text and .data sections
↳.
A csect is the smallest, indivisible unit of code or data.
By default, AIX does not have section start/stop symbols, but the most recent
versions of the linker added a new -bdbg:namedsects:ss flag which enables
section start/stop symbols
↳.
This flag can be set with -C link-arg=-bdbg:namedsects:ss (or by upgrading to
a recent Rust version that sets this automatically
↳
to support link sections.
The linker will report an error like this if the start/stop symbols are not found:
= note: ld: 0711-317 ERROR: Undefined symbol: __start__data_link_section_DATABASES
ld: 0711-317 ERROR: Undefined symbol: __stop__data_link_section_DATABASES
ld: 0711-345 Use the -bloadmap or -bnoquiet option to obtain more information.
For debugging AIX link-section issues, -C link-arg=-bmap:[path]/linker.out
and -C link-arg=-bnoquiet may also be useful.
AIX supports a special mode to strip (strip -r) that preserves structural
symbols like csects and exports. A future version of link-section may add
support for loading csect bounds from the binary's symbol table.
[target.powerpc64-ibm-aix]
rustflags = [
"-C", "link-arg=-bdbg:namedsects:ss", # required
"-C", "link-arg=-bmap:linker.out", # for debugging
"-C", "link-arg=-bnoquiet", # for debugging
]
Typed Sections
Typed sections provide a section where all items are of a specific, sized type. The typed section may be accessed as a slice of the type at zero cost if desired.
A typed section can be created from either static or const items.
For const items: a copy of the const is materialized at link time, while the
constant itself remains available for use as a constant in const contexts.
For static items: the static is stored directly in the link section.
fn items are special-cased and stored as function pointers in the typed
section.
Usage
Create an untyped section using the #[section] macro that keeps related items
in close proximity:
use link_section::{in_section, section};
#[section]
pub static CODE_SECTION: link_section::Section;
#[in_section(CODE_SECTION)]
pub fn link_section_function() {
println!("link_section_function");
}
Create a typed section using the #[section] macro that stores items of a
specific, sized type from static or const items:
mod my_registry {
use link_section::{in_section, section};
pub struct MyStruct {
name: &'static str,
}
#[section]
pub static MY_REGISTRY: link_section::TypedSection<MyStruct>;
// Registers a `const` item.
mod register_a_constant {
use super::*;
// A copy of this constant is registered in the link section.
#[in_section(MY_REGISTRY)]
pub const LINKED_MY_STRUCT: MyStruct = MyStruct { name: "my_struct" };
}
// Registers a `static` item.
mod register_a_static {
use super::*;
// This static lives directly in the link section.
#[in_section(MY_REGISTRY)]
pub static LINKED_MY_STRUCT: MyStruct = MyStruct { name: "my_struct_2" };
}
}
Inspiration
link-section was originally inspired by the linkme project.