pub macro sym_static {
    (
        // A trait item
        #[sym($sym_name:ident)]
        $(#[$meta:meta])*
        $vis:vis fn $fn_name:ident() -> &$ty:ty
    ) => { ... },
    (
        // A concrete definition
        #[sym($sym_name:ident)]
        $(#[$meta:meta])*
        $vis:vis fn $fn_name:ident() -> &$ty:ty { &$static:path }
    ) => { ... },
}
Expand description

Define two fn items representing the specified static variable.

  • $fn_name is a normal function just returning a 'static reference to that variable.

  • $sym_name is not really a function but an immutable variable holding the address of that variable. Inline assembly code can refer to this by a sym operand, but when doing this, it must append _ (an underscore) to the symbol name (see the following example).

Examples

#![feature(naked_functions)]
#![feature(asm_const)]
use r3_portkit::sym::sym_static;
use std::{arch::asm, cell::Cell};

struct InteriorMutable(Cell<usize>);
unsafe impl Sync for InteriorMutable {}

trait Tr {
    sym_static!(#[sym(p_var)] fn var() -> &InteriorMutable);
}

static S: InteriorMutable = InteriorMutable(Cell::new(0));

impl Tr for u8 {
    sym_static!(#[sym(p_var)] fn var() -> &InteriorMutable { &S });
}

// TODO: Replace with the following when const arguments become
//       inferrable:
//
//       let sr1: SymStatic<InteriorMutable, _> = u8::VAR;
let sr = u8::var();
sr.0.set(42);
assert_eq!(sr.0.get(), 42);

// Since it appears as a `fn` item, it can be passed to `asm!` by a
// `sym` input.
let got_value: usize;
#[cfg(target_arch = "x86_64")]
#[cfg(target_os = "linux")]
unsafe {
    asm!("
        mov {0}, qword ptr [rip + {1}_@GOTPCREL]
        mov {0}, qword ptr [{0}]
        mov {0}, qword ptr [{0}]",
        out(reg) got_value, sym u8::p_var,
    );
}
#[cfg(target_arch = "x86_64")]
#[cfg(not(target_os = "linux"))]
unsafe {
    asm!("
        mov {0}, qword ptr [rip + {1}_]
        mov {0}, qword ptr [{0}]",
        out(reg) got_value, sym u8::p_var,
    )
};
#[cfg(target_arch = "aarch64")]
#[cfg(target_os = "macos")]
unsafe {
    asm!("
        adrp {0}, {1}_@PAGE
        ldr {0}, [{0}, {1}_@PAGEOFF]
        ldr {0}, [{0}]
        ",
        out(reg) got_value, sym u8::p_var
    );
}
#[cfg(target_arch = "aarch64")]
#[cfg(not(target_os = "macos"))]
unsafe {
    asm!("
        adrp {0}, :got:{1}_
        ldr {0}, [{0}, #:got_lo12:{1}_]
        ldr {0}, [{0}]
        ldr {0}, [{0}]
        ",
        out(reg) got_value, sym u8::p_var
    )
};
assert_eq!(got_value, 42);