Skip to content

Commit eaaa0bc

Browse files
committed
Blog post on new inline assembly syntax
1 parent 610aa7e commit eaaa0bc

File tree

1 file changed

+130
-0
lines changed

1 file changed

+130
-0
lines changed
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
---
2+
layout: post
3+
title: "New inline assembly syntax available in nightly"
4+
author: Josh Triplett
5+
description: "Rust has a new inline assembly syntax in nightly, please test"
6+
team: the language team <https://www.rust-lang.org/governance/teams/lang>
7+
---
8+
9+
In the course of optimization, OS or embedded development, or other kinds of
10+
low-level programming, you may sometimes need to write native assembly code for
11+
the processor you're running on. "Inline assembly" provides a simple way to
12+
integrate some assembly instructions into a Rust program, feeding Rust
13+
expressions in as input registers, and getting output directly into Rust
14+
variables. We've introduced a new syntax for inline assembly in nightly Rust,
15+
and we're seeking feedback on it; we believe this new syntax has a path to
16+
stabilization in the future.
17+
18+
Nightly Rust has had a syntax for "inline assembly" (`asm!`) for a long time;
19+
however, this syntax just exposed a very raw version of LLVM's assembly
20+
construct, with no safeguards to help developers use it. Getting any detail of
21+
this syntax even slightly wrong tended to produce an Internal Compiler Error
22+
(ICE) rather than the kind of friendly error message you've come to expect from
23+
rustc. This syntax also had little to no hope of being supported on any
24+
non-LLVM backend. As a result of these limitations, the `asm!` syntax was
25+
highly unlikely to ever graduate from nightly to stable Rust, despite it being
26+
one of the most requested features.
27+
28+
In an effort to improve `asm!` and bring it to more users, [Amanieu
29+
d'Antras](https://github.com/Amanieu) designed and implemented a new,
30+
friendlier syntax for `asm!`. This syntax has had a long road:
31+
- The proposal first started as a [pre-RFC on
32+
internals](https://internals.rust-lang.org/t/pre-rfc-2-inline-assembly/11310).
33+
- Inline assembly became the language team's first [project
34+
group](https://github.com/rust-lang/rfcs/blob/master/text/2836-project-asm.md),
35+
and iteratively designed RFCs in [the project group
36+
repository](https://github.com/rust-lang/project-inline-asm/).
37+
- [RFC 2873](https://github.com/rust-lang/rfcs/pull/2873) (still under
38+
discussion) provides a specification for the syntax and its interaction with
39+
the Rust language.
40+
- We [renamed the existing `asm!` to
41+
`llvm_asm!`](https://github.com/rust-lang/rust/pull/68404), so that people
42+
currently using inline assembly on nightly can continue to use the existing
43+
syntax for now. (We plan to remove this syntax eventually, given its fragile
44+
ICE-happy nature, but while evaluating the new syntax we want the old syntax
45+
available for comparison and alternatives.)
46+
- [PR 69171](https://github.com/rust-lang/rust/pull/69171) (also by Amanieu)
47+
implemented the new `asm!` syntax in nightly.
48+
49+
Here's an example of using the new inline assembly syntax, to print a message
50+
to standard output using a direct [`write`
51+
syscall](https://man7.org/linux/man-pages/man2/write.2.html) on x86-64 Linux:
52+
53+
```rust
54+
#![feature(asm)]
55+
56+
fn main() {
57+
let buf = "Hello from asm!\n";
58+
let ret: i32;
59+
unsafe {
60+
asm!(
61+
"syscall",
62+
in("rax") 1, // syscall number
63+
in("rdi") 1, // fd
64+
in("rsi") buf.as_ptr(),
65+
in("rdx") buf.len(),
66+
out("rcx") _, // clobbered by syscalls
67+
out("r11") _, // clobbered by syscalls
68+
lateout("rax") ret,
69+
);
70+
}
71+
println!("write returned: {}", ret);
72+
}
73+
```
74+
75+
(You can [try this example on the
76+
playground](https://play.rust-lang.org/?version=nightly&mode=release&edition=2018&gist=e983a5f5cffa51f4320f1176465d3a56).)
77+
78+
The example above specifies the exact inputs, outputs, and clobbers required by
79+
the Linux syscall calling convention. You can also provide inputs and outputs
80+
via arbitrary registers, and the compiler will select appropriate registers for
81+
you. The following example uses [bit manipulation
82+
instructions](https://en.wikipedia.org/wiki/Bit_Manipulation_Instruction_Sets)
83+
to compute the bit numbers of all set bits in a value, and stores them in a
84+
slice of memory:
85+
86+
```rust
87+
#![feature(asm)]
88+
89+
fn main() {
90+
let mut bits = [0u8; 64];
91+
for value in 0..=1024u64 {
92+
let popcnt;
93+
unsafe {
94+
asm!("
95+
popcnt {popcnt}, {v}
96+
2:
97+
blsi rax, {v}
98+
jz 1f
99+
xor {v}, rax
100+
tzcnt rax, rax
101+
stosb
102+
jmp 2b
103+
1:
104+
",
105+
v = inout(reg) value => _,
106+
popcnt = out(reg) popcnt,
107+
out("rax") _, // scratch
108+
inout("rdi") bits.as_mut_ptr() => _,
109+
);
110+
}
111+
println!("bits of {}: {:?}", value, &bits[0..popcnt]);
112+
}
113+
}
114+
```
115+
116+
(You can [try this example on the
117+
playground](https://play.rust-lang.org/?version=nightly&mode=release&edition=2018&gist=38874735e48aa20289f23f5a3cbeae0c).
118+
Note that this code serves to demonstrate inline assembly, not to demonstrate
119+
an efficient implementation of any particular algorithm.)
120+
121+
Notice that `value` and `popcnt` have registers selected for them, while
122+
`bits.as_mut_ptr()` must go in the `rdi` register for use with the `stosb`
123+
instruction.
124+
125+
For full details on the new `asm!` syntax, see [RFC
126+
2873](https://github.com/Amanieu/rfcs/blob/inline-asm/text/0000-inline-asm.md).
127+
Please try it out, and [report any bugs via the rust issue
128+
tracker](https://github.com/rust-lang/rust/issues/) with the tag `F-asm`. You
129+
can also [report your experiences on the tracking
130+
issue](https://github.com/rust-lang/rust/issues/72016).

0 commit comments

Comments
 (0)