Skip to content

Commit ebd895a

Browse files
authored
Merge pull request #600 from joshtriplett/new-asm
Blog post on new inline assembly syntax
2 parents 69a0a35 + 28e3167 commit ebd895a

File tree

1 file changed

+135
-0
lines changed

1 file changed

+135
-0
lines changed
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
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 was also error-prone for another reason: it looks similar to
24+
GCC's inline assembly syntax, but has subtle differences (such as the names in
25+
register constraints). This syntax also had little to no hope of being
26+
supported on any non-LLVM backend. As a result of all these limitations, the
27+
`asm!` syntax was highly unlikely to ever graduate from nightly to stable Rust,
28+
despite being one of the most requested features.
29+
30+
In an effort to improve `asm!` and bring it to more users, [Amanieu
31+
d'Antras](https://github.com/Amanieu) designed and implemented a new,
32+
friendlier syntax for `asm!`. This syntax has had a long road from concept to
33+
compiler implementation:
34+
- The proposal first started as a [pre-RFC on
35+
internals](https://internals.rust-lang.org/t/pre-rfc-2-inline-assembly/11310).
36+
- Inline assembly became one of the language team's first [project
37+
groups](https://github.com/rust-lang/rfcs/blob/master/text/2836-project-asm.md),
38+
and iteratively designed RFCs in [the project group
39+
repository](https://github.com/rust-lang/project-inline-asm/).
40+
- [RFC 2873](https://github.com/rust-lang/rfcs/pull/2873) (still under
41+
discussion) provides a specification for the syntax and its interaction with
42+
the Rust language.
43+
- We [renamed the existing `asm!` to
44+
`llvm_asm!`](https://github.com/rust-lang/rust/pull/68404), so that people
45+
currently using inline assembly on nightly can continue to use the existing
46+
syntax for now. (We plan to remove this syntax eventually, given its fragile
47+
ICE-happy nature, but while evaluating the new syntax we want the old syntax
48+
available for comparison and alternatives.)
49+
- [PR 69171](https://github.com/rust-lang/rust/pull/69171) (also by Amanieu)
50+
implemented the new `asm!` syntax in nightly.
51+
52+
Here's an example of using the new inline assembly syntax, to print a message
53+
to standard output using a direct [`write`
54+
syscall](https://man7.org/linux/man-pages/man2/write.2.html) on x86-64 Linux:
55+
56+
```rust
57+
#![feature(asm)]
58+
59+
fn main() {
60+
let buf = "Hello from asm!\n";
61+
let ret: i32;
62+
unsafe {
63+
asm!(
64+
"syscall",
65+
in("rax") 1, // syscall number
66+
in("rdi") 1, // fd (stdout)
67+
in("rsi") buf.as_ptr(),
68+
in("rdx") buf.len(),
69+
out("rcx") _, // clobbered by syscalls
70+
out("r11") _, // clobbered by syscalls
71+
lateout("rax") ret,
72+
);
73+
}
74+
println!("write returned: {}", ret);
75+
}
76+
```
77+
78+
(You can [try this example on the
79+
playground](https://play.rust-lang.org/?version=nightly&mode=release&edition=2018&gist=e983a5f5cffa51f4320f1176465d3a56).)
80+
81+
The example above specifies the exact inputs, outputs, and clobbers required by
82+
the Linux syscall calling convention. You can also provide inputs and outputs
83+
via arbitrary registers, and the compiler will select appropriate registers for
84+
you. The following example uses [bit manipulation
85+
instructions](https://en.wikipedia.org/wiki/Bit_Manipulation_Instruction_Sets)
86+
to compute the bit numbers of all set bits in a value, and stores them in a
87+
slice of memory:
88+
89+
```rust
90+
#![feature(asm)]
91+
92+
fn main() {
93+
let mut bits = [0u8; 64];
94+
for value in 0..=1024u64 {
95+
let popcnt;
96+
unsafe {
97+
asm!("
98+
popcnt {popcnt}, {v}
99+
2:
100+
blsi rax, {v}
101+
jz 1f
102+
xor {v}, rax
103+
tzcnt rax, rax
104+
stosb
105+
jmp 2b
106+
1:
107+
",
108+
v = inout(reg) value => _,
109+
popcnt = out(reg) popcnt,
110+
out("rax") _, // scratch
111+
inout("rdi") bits.as_mut_ptr() => _,
112+
);
113+
}
114+
println!("bits of {}: {:?}", value, &bits[0..popcnt]);
115+
}
116+
}
117+
```
118+
119+
(You can [try this example on the
120+
playground](https://play.rust-lang.org/?version=nightly&mode=release&edition=2018&gist=38874735e48aa20289f23f5a3cbeae0c).
121+
Note that this code serves to demonstrate inline assembly, not to demonstrate
122+
an efficient implementation of any particular algorithm.)
123+
124+
Notice that `value` and `popcnt` have registers selected for them, while
125+
`bits.as_mut_ptr()` must go in the `rdi` register for use with the `stosb`
126+
instruction.
127+
128+
For full details on the new `asm!` syntax, see [RFC
129+
2873](https://github.com/Amanieu/rfcs/blob/inline-asm/text/0000-inline-asm.md).
130+
Please try it out (including translating existing inline assembly to the new
131+
syntax), and [report any bugs via the rust issue
132+
tracker](https://github.com/rust-lang/rust/issues/) with the tag `F-asm`. You
133+
can also discuss inline assembly by creating a topic on [the project-inline-asm
134+
stream in
135+
Zulip](https://rust-lang.zulipchat.com/#narrow/stream/216763-project-inline-asm).

0 commit comments

Comments
 (0)