rsymtab/
lib.rs

1//! this is a crate for generating a list of exported symbols, similar to how the `ksymtab` works in the linux kernel, but for
2//! rust crates.
3//!
4//! the basic idea is that you can export items by adding an `#[export]` attribute on them, and then you can access
5//! all the exported symbols by calling the [`symbols`] function.
6//!
7//! # Example
8//!
9//! ```
10//! fn main() {
11//!     println!("{:?}", rsymtab::symbols());
12//! }
13//!
14//! #[rsymtab::export]
15//! fn foo() {}
16//!
17//! #[rsymtab::export]
18//! fn bar() {}
19//!
20//! #[rsymtab::export]
21//! static mut FOO: u32 = 5;
22//! ```
23//!
24//! # Portability
25//!
26//! **NOTE: this crate currently only works on linux.**
27//!
28//! that is because it uses a linker script to achieve some of the magic of creating the symbol table.
29//! additionally, only linkers which support specification of multiple linker scripts are supported, because otherwise this crate
30//! will overwrite the default linker script.
31
32#![no_std]
33
34pub use rsymtab_macros::export;
35
36extern "C" {
37    static __start_rsymtab: *mut ();
38    static __stop_rsymtab: *mut ();
39}
40
41fn align_down(value: usize, alignment: usize) -> usize {
42    (value / alignment) * alignment
43}
44
45/// returns a list of all the exported symbols
46pub fn symbols() -> &'static [RsymtabSymbol] {
47    let start = unsafe { &__start_rsymtab } as *const _ as usize;
48    let unaligned_end = unsafe { &__stop_rsymtab } as *const _ as usize;
49    let unaligned_len_in_bytes = unaligned_end - start;
50    let len_in_bytes = align_down(
51        unaligned_len_in_bytes,
52        core::mem::size_of::<RsymtabSymbol>(),
53    );
54    let len = len_in_bytes / core::mem::size_of::<RsymtabSymbol>();
55    unsafe { core::slice::from_raw_parts(start as *const RsymtabSymbol, len) }
56}
57
58/// an empty placeholder static variable that is placed in the rsymtab section just to make sure that the section exists, to avoid
59/// linker errors.
60#[link_section = "rsymtab"]
61#[allow(dead_code)]
62static PLACE_HOLDER: () = ();
63
64/// an exported symbol
65#[derive(Debug)]
66#[repr(C)]
67pub struct RsymtabSymbol {
68    /// the name of the symbol
69    pub name: &'static str,
70
71    /// the address of the symbol
72    pub address: SymbolAddress,
73}
74
75/// the address of an exported symbol
76#[repr(transparent)]
77pub struct SymbolAddress(&'static ());
78impl SymbolAddress {
79    /// an internal function used for constructing a symbol address object from a reference.
80    #[doc(hidden)]
81    pub const fn _from_reference(reference: &'static ()) -> Self {
82        Self(reference)
83    }
84
85    /// returns a pointer to the symbol
86    pub fn as_ptr(&self) -> *const () {
87        self.0 as *const ()
88    }
89
90    /// returns a mutable pointer to the symbol
91    pub fn as_mut_ptr(&self) -> *mut () {
92        self.0 as *const () as *mut ()
93    }
94
95    /// returns the address of the symbol as a `usize`.
96    pub fn as_usize(&self) -> usize {
97        self.as_ptr() as usize
98    }
99}
100impl core::fmt::Debug for SymbolAddress {
101    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
102        write!(f, "0x{:x}", self.as_usize())
103    }
104}
105impl core::fmt::Display for SymbolAddress {
106    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
107        write!(f, "0x{:x}", self.as_usize())
108    }
109}