How to Use Inline Assembly in Rust

You use inline assembly in Rust via the `asm!` macro (available in nightly Rust) or the `std::arch::asm` module, which allows you to embed assembly instructions directly into your code while maintaining type safety and memory safety guarantees.

You use inline assembly in Rust via the asm! macro (available in nightly Rust) or the std::arch::asm module, which allows you to embed assembly instructions directly into your code while maintaining type safety and memory safety guarantees. You must specify input and output operands, clobbered registers, and the assembly dialect (AT&T or Intel) to ensure the compiler correctly optimizes around your code.

Here is a practical example using the asm! macro on nightly Rust to add two integers using x86-64 assembly:

#![feature(asm)]

fn add_asm(a: i32, b: i32) -> i32 {
    let mut result: i32;
    unsafe {
        asm!(
            "add {0}, {1}",
            out(reg) result,
            in(reg) a,
            in(reg) b,
            options(nostack, pure, readonly)
        );
    }
    result
}

fn main() {
    println!("Result: {}", add_asm(10, 20));
}

In this example, out(reg) tells the compiler to allocate a register for the output, while in(reg) passes the input values. The options clause informs the compiler that the assembly does not modify the stack (nostack), has no side effects (pure), and does not read memory (readonly), enabling better optimization.

For more complex scenarios involving memory operands or specific register constraints, you can use the lateout or inout modifiers. Here is an example that modifies a value in place using the Intel syntax:

#![feature(asm)]

fn increment_in_place(val: &mut i32) {
    unsafe {
        asm!(
            "inc {0}",
            inout(reg) val,
            options(nostack, pure)
        );
    }
}

Note that inline assembly is currently unstable and requires the asm feature flag. It is primarily intended for performance-critical code, hardware interaction, or implementing functions not available in standard Rust. Always ensure you understand the calling conventions and register usage for your target architecture, as incorrect clobber lists can lead to undefined behavior. If you are targeting multiple architectures, consider using the std::arch module with #[target_feature] for portable intrinsics instead of raw assembly, as it provides better cross-platform support and compiler optimization.