riscv_minimal_rt_macros/
lib.rs1#![deny(warnings)]
2
3extern crate proc_macro;
4extern crate rand;
5#[macro_use]
6extern crate quote;
7extern crate core;
8extern crate proc_macro2;
9#[macro_use]
10extern crate syn;
11
12use proc_macro2::Span;
13use rand::Rng;
14use rand::SeedableRng;
15use std::sync::atomic::{AtomicUsize, Ordering};
16use std::time::{SystemTime, UNIX_EPOCH};
17use syn::{
18 parse, spanned::Spanned, Ident, ItemFn, ReturnType, Type, Visibility,
19};
20
21static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
22
23use proc_macro::TokenStream;
24
25#[proc_macro_attribute]
57pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
58 let f = parse_macro_input!(input as ItemFn);
59
60 let valid_signature = f.constness.is_none()
62 && f.vis == Visibility::Inherited
63 && f.abi.is_none()
64 && f.decl.inputs.is_empty()
65 && f.decl.generics.params.is_empty()
66 && f.decl.generics.where_clause.is_none()
67 && f.decl.variadic.is_none()
68 && match f.decl.output {
69 ReturnType::Default => false,
70 ReturnType::Type(_, ref ty) => match **ty {
71 Type::Never(_) => true,
72 _ => false,
73 },
74 };
75
76 if !valid_signature {
77 return parse::Error::new(
78 f.span(),
79 "`#[entry]` function must have signature `[unsafe] fn() -> !`",
80 )
81 .to_compile_error()
82 .into();
83 }
84
85 if !args.is_empty() {
86 return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
87 .to_compile_error()
88 .into();
89 }
90
91 let attrs = f.attrs;
93 let unsafety = f.unsafety;
94 let hash = random_ident();
95 let stmts = f.block.stmts;
96
97 quote!(
98 #[export_name = "main"]
99 #(#attrs)*
100 pub #unsafety fn #hash() -> ! {
101 #(#stmts)*
102 }
103 )
104 .into()
105}
106
107#[proc_macro_attribute]
132pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream {
133 let f = parse_macro_input!(input as ItemFn);
134
135 let valid_signature = f.constness.is_none()
137 && f.vis == Visibility::Inherited
138 && f.unsafety.is_some()
139 && f.abi.is_none()
140 && f.decl.inputs.is_empty()
141 && f.decl.generics.params.is_empty()
142 && f.decl.generics.where_clause.is_none()
143 && f.decl.variadic.is_none()
144 && match f.decl.output {
145 ReturnType::Default => true,
146 ReturnType::Type(_, ref ty) => match **ty {
147 Type::Tuple(ref tuple) => tuple.elems.is_empty(),
148 _ => false,
149 },
150 };
151
152 if !valid_signature {
153 return parse::Error::new(
154 f.span(),
155 "`#[pre_init]` function must have signature `unsafe fn()`",
156 )
157 .to_compile_error()
158 .into();
159 }
160
161 if !args.is_empty() {
162 return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
163 .to_compile_error()
164 .into();
165 }
166
167 let attrs = f.attrs;
169 let ident = f.ident;
170 let block = f.block;
171
172 quote!(
173 #[export_name = "__pre_init"]
174 #(#attrs)*
175 pub unsafe fn #ident() #block
176 )
177 .into()
178}
179
180fn random_ident() -> Ident {
182 let secs = SystemTime::now()
183 .duration_since(UNIX_EPOCH)
184 .unwrap()
185 .as_secs();
186
187 let count: u64 = CALL_COUNT.fetch_add(1, Ordering::SeqCst) as u64;
188 let mut seed: [u8; 16] = [0; 16];
189
190 for (i, v) in seed.iter_mut().take(8).enumerate() {
191 *v = ((secs >> (i * 8)) & 0xFF) as u8
192 }
193
194 for (i, v) in seed.iter_mut().skip(8).enumerate() {
195 *v = ((count >> (i * 8)) & 0xFF) as u8
196 }
197
198 let mut rng = rand::rngs::SmallRng::from_seed(seed);
199 Ident::new(
200 &(0..16)
201 .map(|i| {
202 if i == 0 || rng.gen() {
203 ('a' as u8 + rng.gen::<u8>() % 25) as char
204 } else {
205 ('0' as u8 + rng.gen::<u8>() % 10) as char
206 }
207 })
208 .collect::<String>(),
209 Span::call_site(),
210 )
211}