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}