# Portable `#[link_section]` for Rust
A macro to provide support for portable `#[link_section]` annotations in Rust.
This respects the following binary file formats:
- [ELF](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format)
- [Mach-O](https://en.wikipedia.org/wiki/Mach-O)
- [COFF](https://en.wikipedia.org/wiki/COFF)
## Usage
In essence the `#[portable_link_section]` macro is a restricted version of `#[link_section]`.
The `#[portable_link_section]` macro accepts one of the following `segment` identifiers:
- `text`: code
- `data`: writable data
- `rodata`: read-only data
- `bss`: zero-initialized data
When given `text` or `data` the macro expects another `group` identifier that has to follow some strict rules to provide portability.
Interpreters might have a use for portable `#[link_section]` in order to have more control where certain operator handler functions are placed in memory in order to improve I-cache efficiency by grouping hot and cold code.
## Examples
### Apply `text` on `fn` items.
```rust
#[portable_link_section(text(hot))]
fn func_0() {}
#[portable_link_section(text(cold_i32))]
fn func_1(lhs: i32, rhs: i32) -> i32 {
lhs.wrapping_add(rhs)
}
```
### Apply `data`, `rodata` or `bss` on `static` items.
```rust
#[portable_link_section(data(my_group))]
static DATA_0: i32 = 42;
#[portable_link_section(rodata)]
static DATA_1: i32 = 42;
#[portable_link_section(bss)]
static DATA_2: i32 = 0;
```
### Strict Rules Examples
Certain `group` identifiers have special meaning on some platforms,
therefore their usage is forbidden as to not end up with non-conformant
semantics across platforms.
```rust
#[portable_link_section(text(const))] // ~ERROR: const is reserved for `text` in MACH-O and therefore forbidden
fn func_0() {}
#[portable_link_section(data(common))] // ~ERROR: common is reserved for `data` in MACH-O and therefore forbidden
static DATA_0: i32 = 42;
```
The MACH-O file format has a strict limit on the structure of link section identifiers
as their length is capped to 16 bytes. Since they are represented as zero-terminated strings
we allow a maximum of 15 bytes per `group` identifier.
```rust
#[portable_link_section(text(this_group_identifier_is_too_long))] // ~ERROR: MACH-O has a limit of 15 bytes per identifier
fn func_0() {}
```
### Macro Expansion
The following Rust code that uses the `#[portable_link_section]`:
```rust
#[portable_link_section(text(hot))]
fn func_0() {}
```
Gets expanded into the following Rust code:
```rust
#[cfg_attr(
all(target_family = "unix", not(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))),
unsafe(link_section = ".text.hot"),
)]
#[cfg_attr(
any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"),
unsafe(link_section = "__TEXT,__hot"),
)]
#[cfg_attr(
target_os = "windows",
unsafe(link_section = ".text$hot"),
)]
fn func_0() {}
```
## License
Licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or <https://www.apache.org/licenses/LICENSE-2.0>)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or <https://opensource.org/licenses/MIT>)
at your option.