]>
Commit | Line | Data |
---|---|---|
c34b1796 AL |
1 | % Inline Assembly |
2 | ||
3 | For extremely low-level manipulations and performance reasons, one | |
4 | might wish to control the CPU directly. Rust supports using inline | |
5 | assembly to do this via the `asm!` macro. The syntax roughly matches | |
6 | that of GCC & Clang: | |
7 | ||
8 | ```ignore | |
9 | asm!(assembly template | |
10 | : output operands | |
11 | : input operands | |
12 | : clobbers | |
13 | : options | |
14 | ); | |
15 | ``` | |
16 | ||
17 | Any use of `asm` is feature gated (requires `#![feature(asm)]` on the | |
18 | crate to allow) and of course requires an `unsafe` block. | |
19 | ||
20 | > **Note**: the examples here are given in x86/x86-64 assembly, but | |
21 | > all platforms are supported. | |
22 | ||
23 | ## Assembly template | |
24 | ||
25 | The `assembly template` is the only required parameter and must be a | |
26 | literal string (i.e. `""`) | |
27 | ||
62682a34 | 28 | ```rust |
c34b1796 AL |
29 | #![feature(asm)] |
30 | ||
31 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | |
32 | fn foo() { | |
33 | unsafe { | |
34 | asm!("NOP"); | |
35 | } | |
36 | } | |
37 | ||
38 | // other platforms | |
39 | #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] | |
40 | fn foo() { /* ... */ } | |
41 | ||
42 | fn main() { | |
43 | // ... | |
44 | foo(); | |
45 | // ... | |
46 | } | |
47 | ``` | |
48 | ||
49 | (The `feature(asm)` and `#[cfg]`s are omitted from now on.) | |
50 | ||
51 | Output operands, input operands, clobbers and options are all optional | |
52 | but you must add the right number of `:` if you skip them: | |
53 | ||
62682a34 | 54 | ```rust |
c34b1796 AL |
55 | # #![feature(asm)] |
56 | # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | |
57 | # fn main() { unsafe { | |
58 | asm!("xor %eax, %eax" | |
59 | : | |
60 | : | |
bd371182 | 61 | : "{eax}" |
c34b1796 AL |
62 | ); |
63 | # } } | |
64 | ``` | |
65 | ||
66 | Whitespace also doesn't matter: | |
67 | ||
62682a34 | 68 | ```rust |
c34b1796 AL |
69 | # #![feature(asm)] |
70 | # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | |
71 | # fn main() { unsafe { | |
bd371182 | 72 | asm!("xor %eax, %eax" ::: "{eax}"); |
c34b1796 AL |
73 | # } } |
74 | ``` | |
75 | ||
76 | ## Operands | |
77 | ||
78 | Input and output operands follow the same format: `: | |
79 | "constraints1"(expr1), "constraints2"(expr2), ..."`. Output operand | |
bd371182 | 80 | expressions must be mutable lvalues, or not yet assigned: |
c34b1796 | 81 | |
62682a34 | 82 | ```rust |
c34b1796 AL |
83 | # #![feature(asm)] |
84 | # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | |
85 | fn add(a: i32, b: i32) -> i32 { | |
bd371182 | 86 | let c: i32; |
c34b1796 AL |
87 | unsafe { |
88 | asm!("add $2, $0" | |
89 | : "=r"(c) | |
90 | : "0"(a), "r"(b) | |
91 | ); | |
92 | } | |
93 | c | |
94 | } | |
95 | # #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] | |
96 | # fn add(a: i32, b: i32) -> i32 { a + b } | |
97 | ||
98 | fn main() { | |
99 | assert_eq!(add(3, 14159), 14162) | |
100 | } | |
101 | ``` | |
102 | ||
bd371182 AL |
103 | If you would like to use real operands in this position, however, |
104 | you are required to put curly braces `{}` around the register that | |
105 | you want, and you are required to put the specific size of the | |
106 | operand. This is useful for very low level programming, where | |
107 | which register you use is important: | |
108 | ||
62682a34 | 109 | ```rust |
bd371182 AL |
110 | # #![feature(asm)] |
111 | # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | |
112 | # unsafe fn read_byte_in(port: u16) -> u8 { | |
113 | let result: u8; | |
114 | asm!("in %dx, %al" : "={al}"(result) : "{dx}"(port)); | |
115 | result | |
116 | # } | |
117 | ``` | |
118 | ||
c34b1796 AL |
119 | ## Clobbers |
120 | ||
121 | Some instructions modify registers which might otherwise have held | |
122 | different values so we use the clobbers list to indicate to the | |
123 | compiler not to assume any values loaded into those registers will | |
124 | stay valid. | |
125 | ||
62682a34 | 126 | ```rust |
c34b1796 AL |
127 | # #![feature(asm)] |
128 | # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | |
129 | # fn main() { unsafe { | |
130 | // Put the value 0x200 in eax | |
bd371182 | 131 | asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "{eax}"); |
c34b1796 AL |
132 | # } } |
133 | ``` | |
134 | ||
135 | Input and output registers need not be listed since that information | |
136 | is already communicated by the given constraints. Otherwise, any other | |
137 | registers used either implicitly or explicitly should be listed. | |
138 | ||
139 | If the assembly changes the condition code register `cc` should be | |
140 | specified as one of the clobbers. Similarly, if the assembly modifies | |
141 | memory, `memory` should also be specified. | |
142 | ||
143 | ## Options | |
144 | ||
145 | The last section, `options` is specific to Rust. The format is comma | |
146 | separated literal strings (i.e. `:"foo", "bar", "baz"`). It's used to | |
147 | specify some extra info about the inline assembly: | |
148 | ||
149 | Current valid options are: | |
150 | ||
151 | 1. *volatile* - specifying this is analogous to | |
152 | `__asm__ __volatile__ (...)` in gcc/clang. | |
153 | 2. *alignstack* - certain instructions expect the stack to be | |
154 | aligned a certain way (i.e. SSE) and specifying this indicates to | |
155 | the compiler to insert its usual stack alignment code | |
156 | 3. *intel* - use intel syntax instead of the default AT&T. | |
157 | ||
62682a34 | 158 | ```rust |
bd371182 AL |
159 | # #![feature(asm)] |
160 | # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | |
161 | # fn main() { | |
162 | let result: i32; | |
163 | unsafe { | |
164 | asm!("mov eax, 2" : "={eax}"(result) : : : "intel") | |
165 | } | |
166 | println!("eax is currently {}", result); | |
167 | # } | |
168 | ``` |