Description
Is there a way to explain linker symbols used only for their address? In particular when this address is not meant as a pointer but as an integer only. I have 2 examples.
Example 1: Using a linker symbol to communicate a number
The riscv-rt
crate uses a _heap_size
symbol to let users configure the heap size through the linker script. In particular, they have a code that looks like this in their documentation:
extern "C" {
static _sheap: u8;
static _heap_size: u8;
}
fn main() {
unsafe {
let heap_bottom = &_sheap as *const u8 as usize;
let heap_size = &_heap_size as *const u8 as usize;
some_allocator::initialize(heap_bottom, heap_size);
}
}
We could argue whether u8
is the correct type. Let's assume it's a ZST to simplify this particular case.
Example 2: Using a linker symbol to "allocate" a unique (to the program) value
The defmt
crate uses static variables in specific linker section (with specific name, but this is orthogonal to this issue) to allocate identifiers for interned strings. The address of the static variable (aka the value of the symbol) is the identifier. The static variable does not represent a proper allocation, and actually won't have any allocation at all from Rust point of view (the linker section is NOLOAD
).
The proc-macro generating those static variables looks like this:
quote!(
#[cfg_attr(target_os = "macos", link_section = #section_for_macos)]
#[cfg_attr(not(target_os = "macos"), link_section = #section)]
#[export_name = #sym_name]
static #name: u8 = 0;
)
In this case, the u8
type matters. That's how the identifiers are unique and consecutive (they start at 1 so they can fit in a u16
).
Related issues
I'm creating a new issue, although there are many related issues, because I feel this particular concern of static variables without allocation is not addressed yet. Here are the related issues:
- Wait, how does placing ZST statics work again? #546 overlapping rules for ZST statics
- When are things guaranteed to have unique addresses? #206 unique address guarantee
- Are statics confined to the size indicated by their type? #259 allocation size of static versus size of their type
Please dedup if I missed an issue or I'm wrong in my analysis.
Theoretical suggestion
There could be an attribute to indicate when a static does not have an allocation. It is thus UB for a static to not have an allocation if it does not have this attribute. Such "inaccessible statics" can only have their address taken. They don't have an allocation and can't be dereferenced.
#[inaccessible_static]
static MY_ADDRESS_IS_AN_IDENTIFIER: u8 = 0;
unsafe extern "C" {
#[inaccessible_static]
static MY_ADDRESS_IS_A_VALUE: ();
}