Skip to content

Commit 93bd56b

Browse files
authored
Merge pull request #102 from rust-embedded/update-entry-macro
Change the entry macro to properly hide the main function.
2 parents 0bf8356 + a9b7d8e commit 93bd56b

3 files changed

Lines changed: 49 additions & 57 deletions

File tree

aarch32-rt-macros/src/lib.rs

Lines changed: 42 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use syn::{
3535
/// ```rust
3636
/// #[doc(hidden)]
3737
/// #[export_name = "kmain"]
38-
/// pub unsafe extern "C" fn __cortex_ar_rt_kmain() -> ! {
38+
/// pub unsafe extern "C" fn __aarch32_rt_kmain() -> ! {
3939
/// foo()
4040
/// }
4141
///
@@ -80,10 +80,18 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
8080
.into();
8181
}
8282

83-
let tramp_ident = Ident::new("__cortex_ar_rt_kmain", Span::call_site());
84-
let ident = &f.sig.ident;
85-
86-
if let Err(error) = check_attr_whitelist(&f.attrs, Kind::Entry) {
83+
// This is the name that other Rust code needs to use to call this function -
84+
// we make it long an complicated because no-one is supposed to call this function.
85+
// The `__aarch32_rt` prefix re-inforces this.
86+
//
87+
// However, this is not the symbol that the linker sees - we override that to be
88+
// `kmain` because that's what the start-up assembly code is looking for. As you
89+
// cannot call that symbol without using `extern "C" { }`, it should be sufficiently
90+
// well hidden.
91+
let tramp_ident = Ident::new("__aarch32_rt_kmain", Span::call_site());
92+
let block = f.block;
93+
94+
if let Err(error) = check_attr_whitelist(&f.attrs, VectorKind::Entry) {
8795
return error;
8896
}
8997

@@ -95,10 +103,8 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
95103
#[doc(hidden)]
96104
#[export_name = "kmain"]
97105
pub unsafe extern "C" fn #tramp_ident() -> ! {
98-
#ident()
106+
#block
99107
}
100-
101-
#f
102108
)
103109
.into()
104110
}
@@ -144,7 +150,7 @@ impl std::fmt::Display for Exception {
144150
/// ```rust
145151
/// #[doc(hidden)]
146152
/// #[export_name = "_undefined_handler"]
147-
/// pub unsafe extern "C" fn __cortex_ar_rt_undefined_handler(addr: usize) -> ! {
153+
/// pub unsafe extern "C" fn __aarch32_rt_undefined_handler(addr: usize) -> ! {
148154
/// foo(addr)
149155
/// }
150156
///
@@ -162,7 +168,7 @@ impl std::fmt::Display for Exception {
162168
/// * Irq (creates `_irq_handler`) - although people should prefer `#[irq]`.
163169
#[proc_macro_attribute]
164170
pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
165-
handle_exception_interrupt(args, input, Kind::Exception)
171+
handle_vector(args, input, VectorKind::Exception)
166172
}
167173

168174
/// Creates an `unsafe` interrupt handler.
@@ -184,7 +190,7 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
184190
/// ```rust
185191
/// #[doc(hidden)]
186192
/// #[export_name = "_irq_handler"]
187-
/// pub unsafe extern "C" fn __cortex_ar_rt_irq_handler(addr: usize) -> ! {
193+
/// pub unsafe extern "C" fn __aarch32_rt_irq_handler(addr: usize) -> ! {
188194
/// foo(addr)
189195
/// }
190196
///
@@ -197,12 +203,12 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
197203
/// probably won't consider interrupts to be a form of exception.
198204
#[proc_macro_attribute]
199205
pub fn irq(args: TokenStream, input: TokenStream) -> TokenStream {
200-
handle_exception_interrupt(args, input, Kind::Interrupt)
206+
handle_vector(args, input, VectorKind::Interrupt)
201207
}
202208

203209
/// Note if we got `#[entry]`, `#[exception(...)]` or `#[irq]`
204210
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
205-
enum Kind {
211+
enum VectorKind {
206212
/// Corresponds to `#[entry]`
207213
Entry,
208214
/// Corresponds to `#[exception(...)]`
@@ -212,7 +218,7 @@ enum Kind {
212218
}
213219

214220
/// A common routine for handling exception or interrupt functions
215-
fn handle_exception_interrupt(args: TokenStream, input: TokenStream, kind: Kind) -> TokenStream {
221+
fn handle_vector(args: TokenStream, input: TokenStream, kind: VectorKind) -> TokenStream {
216222
let f = parse_macro_input!(input as ItemFn);
217223

218224
if let Err(error) = check_attr_whitelist(&f.attrs, kind) {
@@ -225,10 +231,10 @@ fn handle_exception_interrupt(args: TokenStream, input: TokenStream, kind: Kind)
225231
};
226232

227233
let exception = match kind {
228-
Kind::Entry => {
229-
panic!("Don't handle #[entry] with `handle_exception_interrupt`!");
234+
VectorKind::Entry => {
235+
panic!("Don't handle #[entry] with `handle_vector`!");
230236
}
231-
Kind::Exception => {
237+
VectorKind::Exception => {
232238
let mut args_iter = args.into_iter();
233239
let Some(TokenTree::Ident(exception_name)) = args_iter.next() else {
234240
return parse::Error::new(
@@ -292,28 +298,27 @@ fn handle_exception_interrupt(args: TokenStream, input: TokenStream, kind: Kind)
292298
}
293299
}
294300
}
295-
Kind::Interrupt => Exception::Irq,
301+
VectorKind::Interrupt => Exception::Irq,
296302
};
297303

298-
let ident = &f.sig.ident;
304+
let block = f.block;
299305
let (ref cfgs, ref attrs) = extract_cfgs(f.attrs.clone());
300306

301307
let handler = match exception {
302308
// extern "C" fn _undefined_handler(addr: usize) -> !;
303309
// unsafe extern "C" fn _undefined_handler(addr: usize) -> usize;
304310
Exception::Undefined => {
305-
let tramp_ident = Ident::new("__cortex_ar_rt_undefined_handler", Span::call_site());
311+
let tramp_ident = Ident::new("__aarch32_rt_undefined_handler", Span::call_site());
306312
if returns_never {
307313
quote!(
308314
#(#cfgs)*
309315
#(#attrs)*
310316
#[doc(hidden)]
311317
#[export_name = "_undefined_handler"]
312318
pub unsafe extern "C" fn #tramp_ident(addr: usize) -> ! {
313-
#ident(addr)
319+
#block
314320
}
315321

316-
#f
317322
)
318323
} else {
319324
quote!(
@@ -322,31 +327,25 @@ fn handle_exception_interrupt(args: TokenStream, input: TokenStream, kind: Kind)
322327
#[doc(hidden)]
323328
#[export_name = "_undefined_handler"]
324329
pub unsafe extern "C" fn #tramp_ident(addr: usize) -> usize {
325-
unsafe {
326-
#ident(addr)
327-
}
330+
#block
328331
}
329332

330-
#f
331333
)
332334
}
333335
}
334336
// extern "C" fn _prefetch_abort_handler(addr: usize) -> !;
335337
// unsafe extern "C" fn _prefetch_abort_handler(addr: usize) -> usize;
336338
Exception::PrefetchAbort => {
337-
let tramp_ident =
338-
Ident::new("__cortex_ar_rt_prefetch_abort_handler", Span::call_site());
339+
let tramp_ident = Ident::new("__aarch32_rt_prefetch_abort_handler", Span::call_site());
339340
if returns_never {
340341
quote!(
341342
#(#cfgs)*
342343
#(#attrs)*
343344
#[doc(hidden)]
344345
#[export_name = "_prefetch_abort_handler"]
345346
pub unsafe extern "C" fn #tramp_ident(addr: usize) -> ! {
346-
#ident(addr)
347+
#block
347348
}
348-
349-
#f
350349
)
351350
} else {
352351
quote!(
@@ -355,30 +354,26 @@ fn handle_exception_interrupt(args: TokenStream, input: TokenStream, kind: Kind)
355354
#[doc(hidden)]
356355
#[export_name = "_prefetch_abort_handler"]
357356
pub unsafe extern "C" fn #tramp_ident(addr: usize) -> usize {
358-
unsafe {
359-
#ident(addr)
360-
}
357+
#block
361358
}
362359

363-
#f
364360
)
365361
}
366362
}
367363
// extern "C" fn _data_abort_handler(addr: usize) -> !;
368364
// unsafe extern "C" fn _data_abort_handler(addr: usize) -> usize;
369365
Exception::DataAbort => {
370-
let tramp_ident = Ident::new("__cortex_ar_rt_data_abort_handler", Span::call_site());
366+
let tramp_ident = Ident::new("__aarch32_rt_data_abort_handler", Span::call_site());
371367
if returns_never {
372368
quote!(
373369
#(#cfgs)*
374370
#(#attrs)*
375371
#[doc(hidden)]
376372
#[export_name = "_data_abort_handler"]
377373
pub unsafe extern "C" fn #tramp_ident(addr: usize) -> ! {
378-
#ident(addr)
374+
#block
379375
}
380376

381-
#f
382377
)
383378
} else {
384379
quote!(
@@ -387,43 +382,35 @@ fn handle_exception_interrupt(args: TokenStream, input: TokenStream, kind: Kind)
387382
#[doc(hidden)]
388383
#[export_name = "_data_abort_handler"]
389384
pub unsafe extern "C" fn #tramp_ident(addr: usize) -> usize {
390-
unsafe {
391-
#ident(addr)
392-
}
385+
#block
393386
}
394-
395-
#f
396387
)
397388
}
398389
}
399390
// extern "C" fn _svc_handler(addr: usize);
400391
Exception::SupervisorCall => {
401-
let tramp_ident = Ident::new("__cortex_ar_rt_svc_handler", Span::call_site());
392+
let tramp_ident = Ident::new("__aarch32_rt_svc_handler", Span::call_site());
402393
quote!(
403394
#(#cfgs)*
404395
#(#attrs)*
405396
#[doc(hidden)]
406397
#[export_name = "_svc_handler"]
407398
pub unsafe extern "C" fn #tramp_ident(arg: u32) {
408-
#ident(arg)
399+
#block
409400
}
410-
411-
#f
412401
)
413402
}
414403
// extern "C" fn _irq_handler(addr: usize);
415404
Exception::Irq => {
416-
let tramp_ident = Ident::new("__cortex_ar_rt_irq_handler", Span::call_site());
405+
let tramp_ident = Ident::new("__aarch32_rt_irq_handler", Span::call_site());
417406
quote!(
418407
#(#cfgs)*
419408
#(#attrs)*
420409
#[doc(hidden)]
421410
#[export_name = "_irq_handler"]
422411
pub unsafe extern "C" fn #tramp_ident() {
423-
#ident()
412+
#block
424413
}
425-
426-
#f
427414
)
428415
}
429416
};
@@ -453,7 +440,7 @@ fn extract_cfgs(attrs: Vec<Attribute>) -> (Vec<Attribute>, Vec<Attribute>) {
453440
}
454441

455442
/// Check whether any disallowed attributes have been applied to our entry/exception function.
456-
fn check_attr_whitelist(attrs: &[Attribute], caller: Kind) -> Result<(), TokenStream> {
443+
fn check_attr_whitelist(attrs: &[Attribute], caller: VectorKind) -> Result<(), TokenStream> {
457444
let whitelist = &[
458445
"doc",
459446
"link_section",
@@ -475,11 +462,11 @@ fn check_attr_whitelist(attrs: &[Attribute], caller: Kind) -> Result<(), TokenSt
475462
}
476463

477464
let err_str = match caller {
478-
Kind::Entry => "this attribute is not allowed on an aarch32-rt entry point",
479-
Kind::Exception => {
465+
VectorKind::Entry => "this attribute is not allowed on an aarch32-rt entry point",
466+
VectorKind::Exception => {
480467
"this attribute is not allowed on an exception handler controlled by aarch32-rt"
481468
}
482-
Kind::Interrupt => {
469+
VectorKind::Interrupt => {
483470
"this attribute is not allowed on an interrupt handler controlled by aarch32-rt"
484471
}
485472
};

aarch32-rt/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,10 @@
115115
//! ```
116116
//!
117117
//! You can also create a 'kmain' function by using the `#[entry]` attribute on
118-
//! a normal Rust function.
118+
//! a normal Rust function. The function will be renamed in such a way that the
119+
//! start-up assembly code can find it, but normal Rust code cannot. Therefore
120+
//! you can be assured that the function will only be called once (unless someone
121+
//! resorts to `unsafe` Rust to import the `kmain` symbol as an `extern "C" fn`).
119122
//!
120123
//! ```rust
121124
//! use aarch32_rt::entry;

examples/mps3-an536/src/bin/gic-priority-ceiling.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,10 @@ fn dump_cpsr() {
9595
println!("CPSR: {:?}", cpsr);
9696
}
9797

98+
// This function doesn't need to be unsafe - I'm just checking you can apply the unsafe
99+
// attribute to it
98100
#[irq]
99-
fn irq_handler() {
101+
unsafe fn irq_handler() {
100102
println!("> IRQ");
101103
while let Some(int_id) = GicCpuInterface::get_and_acknowledge_interrupt(InterruptGroup::Group1)
102104
{

0 commit comments

Comments
 (0)