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