lib.rs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. #![deny(warnings)]
  2. extern crate proc_macro;
  3. extern crate rand;
  4. #[macro_use]
  5. extern crate quote;
  6. extern crate core;
  7. extern crate proc_macro2;
  8. #[macro_use]
  9. extern crate syn;
  10. use proc_macro2::Span;
  11. use rand::Rng;
  12. use rand::SeedableRng;
  13. use std::sync::atomic::{AtomicUsize, Ordering};
  14. use std::time::{SystemTime, UNIX_EPOCH};
  15. use syn::{
  16. parse, spanned::Spanned, Ident, ItemFn, ReturnType, Type, Visibility,
  17. };
  18. static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
  19. use proc_macro::TokenStream;
  20. /// Attribute to declare the entry point of the program
  21. ///
  22. /// **IMPORTANT**: This attribute must appear exactly *once* in the dependency graph. Also, if you
  23. /// are using Rust 1.30 the attribute must be used on a reachable item (i.e. there must be no
  24. /// private modules between the item and the root of the crate); if the item is in the root of the
  25. /// crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31 and newer releases.
  26. ///
  27. /// The specified function will be called by the reset handler *after* RAM has been initialized.
  28. /// If present, the FPU will also be enabled before the function is called.
  29. ///
  30. /// The type of the specified function must be `[unsafe] fn() -> !` (never ending function)
  31. ///
  32. /// # Properties
  33. ///
  34. /// The entry point will be called by the reset handler. The program can't reference to the entry
  35. /// point, much less invoke it.
  36. ///
  37. /// # Examples
  38. ///
  39. /// - Simple entry point
  40. ///
  41. /// ``` no_run
  42. /// # #![no_main]
  43. /// # use riscv_rt_macros::entry;
  44. /// #[entry]
  45. /// fn main() -> ! {
  46. /// loop {
  47. /// /* .. */
  48. /// }
  49. /// }
  50. /// ```
  51. #[proc_macro_attribute]
  52. pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
  53. let f = parse_macro_input!(input as ItemFn);
  54. // check the function signature
  55. let valid_signature = f.sig.constness.is_none()
  56. && f.sig.asyncness.is_none()
  57. && f.vis == Visibility::Inherited
  58. && f.sig.abi.is_none()
  59. && f.sig.inputs.is_empty()
  60. && f.sig.generics.params.is_empty()
  61. && f.sig.generics.where_clause.is_none()
  62. && f.sig.variadic.is_none()
  63. && match f.sig.output {
  64. ReturnType::Default => false,
  65. ReturnType::Type(_, ref ty) => match **ty {
  66. Type::Never(_) => true,
  67. _ => false,
  68. },
  69. };
  70. if !valid_signature {
  71. return parse::Error::new(
  72. f.span(),
  73. "`#[entry]` function must have signature `[unsafe] fn() -> !`",
  74. )
  75. .to_compile_error()
  76. .into();
  77. }
  78. if !args.is_empty() {
  79. return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
  80. .to_compile_error()
  81. .into();
  82. }
  83. // XXX should we blacklist other attributes?
  84. let attrs = f.attrs;
  85. let unsafety = f.sig.unsafety;
  86. let hash = random_ident();
  87. let stmts = f.block.stmts;
  88. quote!(
  89. #[export_name = "main"]
  90. #(#attrs)*
  91. pub #unsafety fn #hash() -> ! {
  92. #(#stmts)*
  93. }
  94. )
  95. .into()
  96. }
  97. /// Attribute to mark which function will be called at the beginning of the reset handler.
  98. ///
  99. /// **IMPORTANT**: This attribute can appear at most *once* in the dependency graph. Also, if you
  100. /// are using Rust 1.30 the attribute must be used on a reachable item (i.e. there must be no
  101. /// private modules between the item and the root of the crate); if the item is in the root of the
  102. /// crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31 and newer
  103. /// releases.
  104. ///
  105. /// The function must have the signature of `unsafe fn()`.
  106. ///
  107. /// The function passed will be called before static variables are initialized. Any access of static
  108. /// variables will result in undefined behavior.
  109. ///
  110. /// # Examples
  111. ///
  112. /// ```
  113. /// # use riscv_rt_macros::pre_init;
  114. /// #[pre_init]
  115. /// unsafe fn before_main() {
  116. /// // do something here
  117. /// }
  118. ///
  119. /// # fn main() {}
  120. /// ```
  121. #[proc_macro_attribute]
  122. pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream {
  123. let f = parse_macro_input!(input as ItemFn);
  124. // check the function signature
  125. let valid_signature = f.sig.constness.is_none()
  126. && f.sig.asyncness.is_none()
  127. && f.vis == Visibility::Inherited
  128. && f.sig.unsafety.is_some()
  129. && f.sig.abi.is_none()
  130. && f.sig.inputs.is_empty()
  131. && f.sig.generics.params.is_empty()
  132. && f.sig.generics.where_clause.is_none()
  133. && f.sig.variadic.is_none()
  134. && match f.sig.output {
  135. ReturnType::Default => true,
  136. ReturnType::Type(_, ref ty) => match **ty {
  137. Type::Tuple(ref tuple) => tuple.elems.is_empty(),
  138. _ => false,
  139. },
  140. };
  141. if !valid_signature {
  142. return parse::Error::new(
  143. f.span(),
  144. "`#[pre_init]` function must have signature `unsafe fn()`",
  145. )
  146. .to_compile_error()
  147. .into();
  148. }
  149. if !args.is_empty() {
  150. return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
  151. .to_compile_error()
  152. .into();
  153. }
  154. // XXX should we blacklist other attributes?
  155. let attrs = f.attrs;
  156. let ident = f.sig.ident;
  157. let block = f.block;
  158. quote!(
  159. #[export_name = "__pre_init"]
  160. #(#attrs)*
  161. pub unsafe fn #ident() #block
  162. )
  163. .into()
  164. }
  165. // Creates a random identifier
  166. fn random_ident() -> Ident {
  167. let secs = SystemTime::now()
  168. .duration_since(UNIX_EPOCH)
  169. .unwrap()
  170. .as_secs();
  171. let count: u64 = CALL_COUNT.fetch_add(1, Ordering::SeqCst) as u64;
  172. let mut seed: [u8; 16] = [0; 16];
  173. for (i, v) in seed.iter_mut().take(8).enumerate() {
  174. *v = ((secs >> (i * 8)) & 0xFF) as u8
  175. }
  176. for (i, v) in seed.iter_mut().skip(8).enumerate() {
  177. *v = ((count >> (i * 8)) & 0xFF) as u8
  178. }
  179. let mut rng = rand::rngs::SmallRng::from_seed(seed);
  180. Ident::new(
  181. &(0..16)
  182. .map(|i| {
  183. if i == 0 || rng.gen() {
  184. ('a' as u8 + rng.gen::<u8>() % 25) as char
  185. } else {
  186. ('0' as u8 + rng.gen::<u8>() % 10) as char
  187. }
  188. })
  189. .collect::<String>(),
  190. Span::call_site(),
  191. )
  192. }