# link-section

![Build Status](https://github.com/mmastrac/rust-ctor/actions/workflows/rust.yml/badge.svg)

| crate          | docs                                                                               | version                                                                                                 |
| -------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| `ctor`         | [![docs.rs](https://docs.rs/ctor/badge.svg)](https://docs.rs/ctor)                 | [![crates.io](https://img.shields.io/crates/v/ctor.svg)](https://crates.io/crates/ctor)                 |
| `dtor`         | [![docs.rs](https://docs.rs/dtor/badge.svg)](https://docs.rs/dtor)                 | [![crates.io](https://img.shields.io/crates/v/dtor.svg)](https://crates.io/crates/dtor)                 |
| `link-section` | [![docs.rs](https://docs.rs/link-section/badge.svg)](https://docs.rs/link-section) | [![crates.io](https://img.shields.io/crates/v/link-section.svg)](https://crates.io/crates/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                     | ⚠️ Only integers can be stored in sections and may require host environment support (§2) (§3) |
| 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 only allows plain bytes in `#[link_section]` statics (no pointers).

(§3) Host environment support (by calling the exported `register_link_section`
function) is required to register each section with the runtime. As a
consequence, the functions available on the `Section` and `TypedSection` types
are not `const`.

## 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](https://devblogs.microsoft.com/oldnewthing/20181107-00/?p=100155) and
[this blog
post](https://devblogs.microsoft.com/oldnewthing/20181108-00/?p=100165) 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.

## 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.

`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:

```rust
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:

```rust
mod my_registry {
    use link_section::{in_section, section};

    pub struct MyStruct {
        name: &'static str,
    }

    #[section]
    pub static MY_REGISTRY: link_section::TypedSection<MyStruct>;

    mod a {
        use super::*;

        #[in_section(MY_REGISTRY)]
        pub static LINKED_MY_STRUCT: MyStruct = MyStruct { name: "my_struct" };
    }

    mod b {
        use super::*;

        #[in_section(MY_REGISTRY)]
        pub static LINKED_MY_STRUCT: MyStruct = MyStruct { name: "my_struct_2" };
    }
}
```
