naked-function 0.1.5

Proc macro implementation of #[naked]
Documentation
#![cfg(target_arch = "arm")]
#![feature(asm_const)]

use std::assert_eq;

#[naked_function::naked]
pub unsafe extern "C" fn add(a: i32, b: i32) -> i32 {
    asm!("add r0, r0, r1", "bx lr");
}

#[test]
fn test_add() {
    let ret = unsafe { add(1, 2) };
    assert_eq!(ret, 3);
}

#[naked_function::naked]
pub unsafe extern "C" fn add_5(a: i32) -> i32 {
    asm!(
        "add r0, r0, #{}",
        "bx lr",
        const 5,
    )
}

#[test]
fn test_const() {
    let ret = unsafe { add_5(3) };
    assert_eq!(ret, 8);
}

extern "C" fn mutate_string(str: &mut String) {
    assert_eq!(str, "hello");
    *str = "world".into();
}

#[allow(improper_ctypes)]
#[naked_function::naked]
pub unsafe extern "C" fn call_sym(str: &mut String) -> i32 {
    asm!(
        "str lr, [sp, #-8]!",
        "bl {}",
        "ldr pc, [sp], #8",
        sym mutate_string
    );
}

#[test]
fn test_sym() {
    let mut str = "hello".to_string();
    unsafe {
        call_sym(&mut str);
    }
    assert_eq!(str, "world");
}

#[naked_function::naked]
#[export_name = "exported_symbol_name"]
pub unsafe extern "C" fn export_name() -> i32 {
    asm!("mov r0, #3", "bx lr");
}

#[test]
fn test_export_name() {
    extern "C" {
        fn exported_symbol_name() -> i32;
    }
    let val = unsafe { exported_symbol_name() };
    assert_eq!(val, 3);
}

#[naked_function::naked]
pub unsafe extern "C" fn mangled() -> i32 {
    asm!("mov r0, #4", "bx lr");
}

mod scoped {
    #[no_mangle]
    fn mangled() -> i32 {
        5
    }
}

#[test]
fn test_mangled() {
    extern "C" {
        fn mangled() -> i32;
    }
    let val = unsafe { mangled() };
    assert_eq!(val, 5);
}

#[naked_function::naked]
#[instruction_set(arm::a32)]
pub unsafe extern "C" fn add_arm(a: i32, b: i32) -> i32 {
    asm!("add r0, r0, r1", "bx lr");
}

#[test]
fn test_arm() {
    let ret = unsafe { add_arm(1, 2) };
    assert_eq!(ret, 3);
    assert_eq!(add_arm as usize & 1, 0);
}

#[naked_function::naked]
#[instruction_set(arm::t32)]
pub unsafe extern "C" fn add_thumb(a: i32, b: i32) -> i32 {
    asm!("add r0, r0, r1", "bx lr");
}

#[test]
fn test_thumb() {
    let ret = unsafe { add_thumb(1, 2) };
    assert_eq!(ret, 3);
    assert_eq!(add_thumb as usize & 1, 1);
}