Rust
Operands
Use in, out and inout operands.
Operands
Operands bind Rust variables to the assembly:
in(reg) x: input only.out(reg) y: output only; its starting value is meaningless.inout(reg) z: both input and output.lateout(reg) y: an output written after all inputs are read; the compiler may reuse an input's register.
let t: u64;
unsafe {
asm!(
"mov {o}, {a}",
"add {o}, {b}",
a = in(reg) 5u64,
b = in(reg) 6u64,
o = out(reg) t,
);
}
// t == 11
Named operands ({a}) make multi-line code readable.
Register classes
reg is the general-purpose register class. Other classes: on x86, xmm_reg, ymm_reg (vector), reg_byte (8-bit). The value's size decides which part of the register is used; to choose explicitly there are template modifiers: {0:e} gives the 32-bit name like eax, {0:r} the 64-bit name like rax.
let mut x: u32 = 0x11223344;
unsafe { asm!("bswap {0:e}", inout(reg) x) }; // 32-bit byte swap
Exercise Named operands
Write the two-instruction example above as fn topla(a: u64, b: u64) -> u64 for x86-64 (a + b on other architectures). Print the result of topla(5, 6).
Show example solution
#[cfg(target_arch = "x86_64")]
fn topla(a: u64, b: u64) -> u64 {
let t: u64;
// SAFETY: yalnızca operand yazmaçlarını kullanır.
unsafe {
std::arch::asm!(
"mov {o}, {a}",
"add {o}, {b}",
a = in(reg) a,
b = in(reg) b,
o = out(reg) t,
);
}
t
}
#[cfg(not(target_arch = "x86_64"))]
fn topla(a: u64, b: u64) -> u64 {
a + b
}
fn main() {
println!("{}", topla(5, 6));
}
Test yourself
-
In the example above, why could using <code>lateout</code> for <code>o</code> be wrong?
- It isn't wrong
- o is written in the first instruction but b hasn't been read yet; the compiler may give o and b the same register
- lateout doesn't exist
- It's slower
Show answer
o is written in the first instruction but b hasn't been read yet; the compiler may give o and b the same register — lateout is only safe for outputs written after all inputs have been used.
-
Output only
asm!(
"mov {o}, {a}",
a = in(reg) 5u64,
o = ____(reg) t,
);
Show answer
asm!(
"mov {o}, {a}",
a = in(reg) 5u64,
o = out(reg) t,
);
-
Operand and direction
- in(reg) x
- Rust → asm
- out(reg) y
- asm → Rust
- inout(reg) z
- Both ways
- lateout(reg) y
- Output after inputs
Next lesson: Registers