Skip to content
This repository was archived by the owner on Nov 28, 2023. It is now read-only.

[WIP] add entry2 attribute #20

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ license = "ISC"
r0 = "0.2.2"
riscv = "0.4.0"

[dependencies.riscv-rt-macros]
path = "macros"
version = "0.1.0"

[features]
const-fn = ["riscv/const-fn"]
inline-asm = ["riscv/inline-asm"]
17 changes: 17 additions & 0 deletions macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
authors = [
"The RISCV Team <[email protected]>",
"Jorge Aparicio <[email protected]>",
]
name = "riscv-rt-macros"
version = "0.1.0"

[lib]
proc-macro = true

[dependencies]
quote = "0.6.11"

[dependencies.syn]
features = ["extra-traits", "full"]
version = "0.15.26"
157 changes: 157 additions & 0 deletions macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
extern crate proc_macro;
extern crate quote;
extern crate syn;

use std::collections::HashSet;

use proc_macro::{Span, TokenStream};
use quote::quote;
use syn::{
parse, parse_macro_input, spanned::Spanned, AttrStyle, Attribute, Item, ItemFn, ItemStatic,
PathArguments, ReturnType, Stmt, Type, Visibility,
};

#[proc_macro_attribute]
pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
let f = parse_macro_input!(input as ItemFn);

// check the function signature
let valid_signature = f.constness.is_none()
&& f.vis == Visibility::Inherited
&& f.abi.is_none()
&& f.decl.inputs.is_empty()
&& f.decl.generics.params.is_empty()
&& f.decl.generics.where_clause.is_none()
&& f.decl.variadic.is_none()
&& match f.decl.output {
ReturnType::Default => false,
ReturnType::Type(_, ref ty) => match **ty {
Type::Never(_) => true,
_ => false,
},
};

if !valid_signature {
return parse::Error::new(
f.span(),
"`#[entry]` function must have signature `[unsafe] fn() -> !`",
)
.to_compile_error()
.into();
}

if !args.is_empty() {
return parse::Error::new(
Span::call_site().into(),
"This attribute accepts no arguments",
)
.to_compile_error()
.into();
}

// XXX should we blacklist other attributes?
let attrs = f.attrs;
let unsafety = f.unsafety;
let ident = f.ident;
let (statics, stmts) = match extract_static_muts(f.block.stmts) {
Err(e) => return e.to_compile_error().into(),
Ok(x) => x,
};

let vars = statics
.into_iter()
.map(|var| {
let (ref cfgs, ref attrs) = extract_cfgs(var.attrs);
let ident = var.ident;
let ty = var.ty;
let expr = var.expr;

quote!(
#[allow(non_snake_case)]
#(#cfgs)*
let #ident: &'static mut #ty = unsafe {
#(#attrs)*
#(#cfgs)*
static mut #ident: #ty = #expr;

&mut #ident
};
)
})
.collect::<Vec<_>>();

quote!(
const #ident: () = {
#[no_mangle]
#(#attrs)*
#unsafety extern "C" fn main() -> ! {
#(#vars)*

#(#stmts)*
}

main()
};
)
.into()
}

/// Extracts `static mut` vars from the beginning of the given statements
fn extract_static_muts(stmts: Vec<Stmt>) -> Result<(Vec<ItemStatic>, Vec<Stmt>), parse::Error> {
let mut istmts = stmts.into_iter();

let mut seen = HashSet::new();
let mut statics = vec![];
let mut stmts = vec![];
while let Some(stmt) = istmts.next() {
match stmt {
Stmt::Item(Item::Static(var)) => {
if var.mutability.is_some() {
if seen.contains(&var.ident) {
return Err(parse::Error::new(
var.ident.span(),
format!("the name `{}` is defined multiple times", var.ident),
));
}

seen.insert(var.ident.clone());
statics.push(var);
} else {
stmts.push(Stmt::Item(Item::Static(var)));
}
}
_ => {
stmts.push(stmt);
break;
}
}
}

stmts.extend(istmts);

Ok((statics, stmts))
}

fn extract_cfgs(attrs: Vec<Attribute>) -> (Vec<Attribute>, Vec<Attribute>) {
let mut cfgs = vec![];
let mut not_cfgs = vec![];

for attr in attrs {
if eq(&attr, "cfg") {
cfgs.push(attr);
} else {
not_cfgs.push(attr);
}
}

(cfgs, not_cfgs)
}

/// Returns `true` if `attr.path` matches `name`
fn eq(attr: &Attribute, name: &str) -> bool {
attr.style == AttrStyle::Outer && attr.path.segments.len() == 1 && {
let pair = attr.path.segments.first().unwrap();
let segment = pair.value();
segment.arguments == PathArguments::None && segment.ident.to_string() == name
}
}
9 changes: 6 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@
//! Disassembly of section .text:
//!
//! 20000000 <_start>:
//! 20000000: 800011b7 lui gp,0x80001
//! 20000004: 80018193 addi gp,gp,-2048 # 80000800 <_stack_start+0xffffc800>
//! 20000008: 80004137 lui sp,0x80004
//! 20000000: 800011b7 lui gp,0x80001
//! 20000004: 80018193 addi gp,gp,-2048 # 80000800 <_stack_start+0xffffc800>
//! 20000008: 80004137 lui sp,0x80004
//! ```
//!
//! # Symbol interfaces
Expand Down Expand Up @@ -187,10 +187,13 @@
#![deny(warnings)]

extern crate riscv;
extern crate riscv_rt_macros;
extern crate r0;

use riscv::register::{mstatus, mtvec};

pub use riscv_rt_macros::entry as entry2;

extern "C" {
// Boundaries of the .bss section
static mut _ebss: u32;
Expand Down