CodeBlanks Logo Icon CodeBlanks

Summary - Inline assembly

Combine asm!, in/out and options to read time with rdtsc.

Inline assembly summary

asm! writes processor instructions inside unsafe. Operands: in, out, inout, lateout; a register class (reg) or an explicit register ("rax"). Clobbered registers are declared with out("..") _ or clobber_abi. options(pure, nomem, nostack, readonly) enables optimization, but correctness is on you. For portability use #[cfg(target_arch)] and a fallback; in most cases std::arch intrinsics or the compiler are enough.

Swapping byte order

bswap reverses the byte order of a 32- or 64-bit value (big-endian ↔ little-endian). Its Rust counterpart is swap_bytes; we can verify the result by comparing with it:

let mut x: u32 = 0x11223344;
unsafe {
    asm!("bswap {0:e}", inout(reg) x, options(pure, nomem, nostack));
}
assert_eq!(x, 0x11223344u32.swap_bytes());   // 0x44332211

{0:e} is for using the 32-bit register name (like eax); it matters because the upper 32 bits may be undefined for a u32 value.

Practice bswap and verification

For x86-64, write fn ters_bayt(x: u32) -> u32 using bswap {0:e} (x.swap_bytes() on other architectures). For 0x11223344, print the result with {:#x} and its equality with swap_bytes, separated by a space.

Starter code

main.rs
fn main() {
    // buraya yaz
}

Sample solution

main.rs
#[cfg(target_arch = "x86_64")]
fn ters_bayt(mut x: u32) -> u32 {
    // SAFETY: bswap yalnızca operand yazmacını değiştirir.
    unsafe {
        std::arch::asm!("bswap {0:e}", inout(reg) x, options(pure, nomem, nostack));
    }
    x
}

#[cfg(not(target_arch = "x86_64"))]
fn ters_bayt(x: u32) -> u32 {
    x.swap_bytes()
}

fn main() {
    let y = ters_bayt(0x11223344);
    println!("{:#x} {}", y, y == 0x11223344u32.swap_bytes());
}

Expected output

0x44332211 true

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 What is a good way to test an assembly block's correctness?

  • It can't be tested
  • Comparing its result with a pure Rust version doing the same job Correct answer
  • Only that it compiles
  • Adding comments

Explanation: The reference implementation is both the fallback path and the test oracle.

2 32-bit register name

Question
asm!("bswap {0:____}", inout(reg) x, options(pure, nomem, nostack));
Answer
asm!("bswap {0:e}", inout(reg) x, options(pure, nomem, nostack));

Explanation: The :e modifier selects the 32-bit register name.

3 Group summary

Term Meaning
asm! Inline instruction
inout Input + output
options(pure) No side-effect promise
swap_bytes Pure Rust counterpart

All lessons in Expert