| // Test that `extern "custom"` functions can be called from assembly, and defined using a naked |
| // function, and `global_asm!` with an `extern "custom"` block. |
| // |
| //@ run-pass |
| //@ only-x86_64 |
| #![feature(abi_custom)] |
| |
| use std::arch::{asm, global_asm, naked_asm}; |
| |
| #[unsafe(naked)] |
| unsafe extern "custom" fn double() { |
| naked_asm!("add rax, rax", "ret"); |
| } |
| |
| global_asm!( |
| // work around macOS prefixing symbols with _ |
| " .globl {0}", |
| "{0}:", |
| " add rax, 1", |
| " ret", |
| sym increment, |
| ); |
| |
| unsafe extern "custom" { |
| fn increment(); |
| } |
| |
| #[repr(transparent)] |
| struct Thing(u64); |
| |
| impl Thing { |
| #[unsafe(naked)] |
| unsafe extern "custom" fn is_even() { |
| naked_asm!("test al, 1", "sete al", "ret"); |
| } |
| } |
| |
| trait BitwiseNot { |
| #[unsafe(naked)] |
| unsafe extern "custom" fn bitwise_not() { |
| naked_asm!("not rax", "ret"); |
| } |
| } |
| |
| impl BitwiseNot for Thing {} |
| |
| #[unsafe(naked)] |
| unsafe extern "C" fn const_generic<const N: u64>() { |
| naked_asm!( |
| "mov rax, {}", |
| "ret", |
| const N, |
| ); |
| } |
| |
| pub fn main() { |
| let mut x: u64 = 21; |
| unsafe { asm!("call {}", sym double, inout("rax") x) }; |
| assert_eq!(x, 42); |
| |
| let mut x: u64 = 41; |
| unsafe { asm!("call {}", sym increment, inout("rax") x) }; |
| assert_eq!(x, 42); |
| |
| let mut x: u8; |
| unsafe { asm!("call {}", sym Thing::is_even, inout("al") 42u8 => x) }; |
| assert!(x != 0); |
| |
| let mut x: u64 = 42; |
| unsafe { asm!("call {}", sym Thing::bitwise_not, inout("rax") x) }; |
| assert_eq!(x, !42); |
| |
| // Create and call in `asm!` an `extern "custom"` function pointer. |
| fn caller(f: unsafe extern "custom" fn(), mut x: u64) -> u64 { |
| unsafe { asm!("call {}", in(reg) f, inout("rax") x) }; |
| x |
| } |
| |
| assert_eq!(caller(double, 2), 4); |
| |
| let x: u64; |
| unsafe { asm!("call {}", sym const_generic::<42>, out("rax") x) }; |
| assert_eq!(x, 42); |
| |
| let x: u64; |
| unsafe { asm!("call {}", sym const_generic::<84>, out("rax") x) }; |
| assert_eq!(x, 84); |
| } |