Rust
Registers
Specify explicit registers.
Explicit registers
Some instructions use specific registers (for example on x86, mul, div, cpuid, system calls). In such cases the register's name is given in quotes instead of a register class:
let mut x: u64 = 6;
let y: u64 = 7;
unsafe {
asm!(
"imul rax, rcx",
inout("rax") x,
in("rcx") y,
);
}
// x == 42
Explicit registers are written in the template by name, not with {}. Some registers (like the stack pointer rsp and the frame pointer rbp) can't be used as operands.
Clobbered registers
mul writes its result to the rdx:rax pair; even if rdx isn't used, it must be declared as clobbered:
let mut a: u64 = 6;
unsafe {
asm!(
"mul {b}",
b = in(reg) 7u64,
inout("rax") a,
out("rdx") _, // rdx clobbered, its value not needed
);
}
For assembly that calls functions, the clobber_abi("C") option declares all registers the calling convention may clobber at once.
Exercise Multiplication with explicit registers
For x86-64, write fn carp(x: u64, y: u64) -> u64 using the instruction imul rax, rcx with explicit registers (x * y on other architectures). Print the result of carp(6, 7).
Show example solution
#[cfg(target_arch = "x86_64")]
fn carp(mut x: u64, y: u64) -> u64 {
// SAFETY: yalnızca rax ve rcx kullanılır ve ikisi de bildirilmiştir.
unsafe {
std::arch::asm!(
"imul rax, rcx",
inout("rax") x,
in("rcx") y,
);
}
x
}
#[cfg(not(target_arch = "x86_64"))]
fn carp(x: u64, y: u64) -> u64 {
x * y
}
fn main() {
println!("{}", carp(6, 7));
}
Test yourself
-
If an instruction clobbers a register whose value you don't use, what should you do?
- Tell the compiler with out("reg_name") _
- Nothing
- Remove unsafe
- Always save and restore the register
Show answer
Tell the compiler with out("reg_name") _ — Changing an undeclared register silently breaks a value the compiler kept there: undefined behaviour.
-
Specific register
asm!(
"imul rax, rcx",
inout(____) x,
in("rcx") y,
);
Show answer
asm!(
"imul rax, rcx",
inout("rax") x,
in("rcx") y,
);
-
Syntax and meaning
- in(reg) x
- Compiler picks a register
- in("rcx") y
- rcx required
- out("rdx") _
- Clobbered register
- clobber_abi("C")
- Calling-convention registers
Next lesson: Options