naked_function_macro/lib.rs
1//! Implementation of the proc macro used by the `naked-function` crate.
2//!
3//! Don't use this crate directly, use the `naked-function` crate instead.
4
5use proc_macro::TokenStream;
6use proc_macro2::TokenStream as TokenStream2;
7
8use quote::ToTokens;
9use syn::{parse::Nothing, parse_macro_input};
10
11macro_rules! bail {
12 ($span:expr, $($tt:tt)*) => {
13 return Err(syn::Error::new_spanned($span, format!($($tt)*)))
14 };
15}
16
17mod asm;
18mod naked;
19
20/// An attribute to define a function written entirely in assembly.
21///
22/// A naked function must contain only a single `asm!` statement: the contents
23/// of this `asm!` becomes the body of the function, with no prologue or
24/// epilogue. This means that the assembly code is responsible for including
25/// the necessary instructions to return from a function.
26///
27/// The primary use of naked function is to implement functions that use a
28/// custom calling convention that is not directly supported by rustc. Examples
29/// include hardware exception handlers, functions called from assembly code
30/// and customizing unwinding metadata.
31///
32/// ## Example
33///
34/// ```rust
35/// # #![cfg(all(target_os = "linux", target_arch = "x86_64"))]
36/// // The SYSV64 calling convention used on x86_64 Linux passes the first
37/// // 2 integer arguments in EDI/ESI.
38/// #[naked_function::naked]
39/// pub unsafe extern "C" fn add(a: i32, b: i32) -> i32 {
40/// asm!(
41/// "lea eax, [edi + esi]",
42/// "ret",
43/// );
44/// }
45///
46/// #[test]
47/// fn main() {
48/// let ret = unsafe { add(1, 2) };
49/// assert_eq!(ret, 3);
50/// }
51/// ```
52///
53/// ## `asm!` restrictions
54///
55/// The `asm!` is further restricted in that:
56/// - Only `sym` and `const` operands are allowed.
57/// - `clobber_abi` cannot be used.
58/// - Only the `raw` and `att_syntax` options can be used.
59///
60/// These are the same set of operands accepted by `global_asm!`, which this
61/// attribute lowers the functions into.
62///
63/// ## Accessing function arguments.
64///
65/// The function signature is indicative only: it is merely there to allow
66/// Rust code to reference and call the naked function.
67///
68/// Function arguments cannot be referenced from the function body directly,
69/// instead you should access these from the expected register/stack slot as
70/// per the function ABI.
71///
72/// Similarly, you are responsible for placing function return values in the
73/// appropriate registers or stack slot for the calling convention used.
74///
75/// ## ABI and attributes
76///
77/// Naked functions must be marked as `unsafe`.
78///
79/// The function must have one of the following whitelisted ABIs:
80/// - `"C"`
81/// - `"C-unwind"`
82///
83/// Only the following attributes are supported on naked functions:
84/// - `#[export_name]`
85/// - `#[no_mangle]`
86/// - `#[link_section]`
87/// - `#[cfg]`
88/// - `#[doc]` or `///` doc comments
89#[proc_macro_attribute]
90pub fn naked(attr: TokenStream, item: TokenStream) -> TokenStream {
91 parse_macro_input!(attr as Nothing);
92 match naked::naked_attribute(&parse_macro_input!(item)) {
93 Ok(items) => {
94 let mut tokens = TokenStream2::new();
95 for item in &items {
96 item.to_tokens(&mut tokens);
97 }
98 tokens.into()
99 }
100 Err(e) => e.to_compile_error().into(),
101 }
102}