CodeBlanks Logo Icon CodeBlanks

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

Practice 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).

Starter code

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

Sample solution

main.rs
#[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));
}

Expected output

11

Questions and answers

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

1 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 Correct answer
  • lateout doesn't exist
  • It's slower

Explanation: lateout is only safe for outputs written after all inputs have been used.

2 Output only

Question
asm!(
    "mov {o}, {a}",
    a = in(reg) 5u64,
    o = ____(reg) t,
);
Answer
asm!(
    "mov {o}, {a}",
    a = in(reg) 5u64,
    o = out(reg) t,
);

Explanation: An out operand carries a value written only by the assembly into Rust.

3 Operand and direction

Term Meaning
in(reg) x Rust → asm
out(reg) y asm → Rust
inout(reg) z Both ways
lateout(reg) y Output after inputs

All lessons in Expert