Rust
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.
Exercise 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.
Show example solution
#[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());
}
Test yourself
-
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
- Only that it compiles
- Adding comments
Show answer
Comparing its result with a pure Rust version doing the same job — The reference implementation is both the fallback path and the test oracle.
-
32-bit register name
asm!("bswap {0:____}", inout(reg) x, options(pure, nomem, nostack));
Show answer
asm!("bswap {0:e}", inout(reg) x, options(pure, nomem, nostack));
-
Group summary
- asm!
- Inline instruction
- inout
- Input + output
- options(pure)
- No side-effect promise
- swap_bytes
- Pure Rust counterpart
Next lesson: no_std