You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -106,6 +110,7 @@ This is different from specifying an input and output separately in that it is g
106
110
It is also possible to specify different variables for the input and output parts of an `inout` operand:
107
111
108
112
```rust
113
+
# #![feature(asm)]
109
114
letx:u64=3;
110
115
lety:u64;
111
116
unsafe {
@@ -127,6 +132,7 @@ There is also a `inlateout` variant of this specifier.
127
132
Here is an example where `inlateout`*cannot* be used:
128
133
129
134
```rust
135
+
# #![feature(asm)]
130
136
letmuta:u64=4;
131
137
letb:u64=4;
132
138
letc:u64=4;
@@ -144,6 +150,7 @@ Here the compiler is free to allocate the same register for inputs `b` and `c` s
144
150
However the following example can use `inlateout` since the output is only modified after all input registers have been read:
145
151
146
152
```rust
153
+
# #![feature(asm)]
147
154
letmuta:u64=4;
148
155
letb:u64=4;
149
156
unsafe {
@@ -161,21 +168,24 @@ Therefore, Rust inline assembly provides some more specific constraint specifier
161
168
While `reg` is generally available on any architecture, these are highly architecture specific. E.g. for x86 the general purpose registers `eax`, `ebx`, `ecx`, `edx`, `ebp`, `esi`, and `edi`
162
169
among others can be addressed by their name.
163
170
164
-
```rust
171
+
```rust,no_run
172
+
# #![feature(asm)]
173
+
let cmd = 0xd1;
165
174
unsafe {
166
-
asm!("out 0x64, rax", in("rax") cmd);
175
+
asm!("out 0x64, eax", in("eax") cmd);
167
176
}
168
177
```
169
178
170
179
In this example we call the `out` instruction to output the content of the `cmd` variable
171
-
to port `0x64`. Since the `out` instruction only accepts `rax` (and its sub registers) as operand
172
-
we had to use the `rax` constraint specifier.
180
+
to port `0x64`. Since the `out` instruction only accepts `eax` (and its sub registers) as operand
181
+
we had to use the `eax` constraint specifier.
173
182
174
183
Note that unlike other operand types, explicit register operands cannot be used in the template string: you can't use `{}` and should write the register name directly instead. Also, they must appear at the end of the operand list after all other operand types.
175
184
176
185
Consider this example which uses the x86 `mul` instruction:
@@ -211,8 +221,9 @@ We need to tell the compiler about this since it may need to save and restore th
211
221
around the inline assembly block.
212
222
213
223
```rust
214
-
letebx:u64;
215
-
letecx:u64;
224
+
# #![feature(asm)]
225
+
letebx:u32;
226
+
letecx:u32;
216
227
217
228
unsafe {
218
229
asm!(
@@ -240,6 +251,7 @@ However we still need to tell the compiler that `eax` and `edx` have been modifi
240
251
This can also be used with a general register class (e.g. `reg`) to obtain a scratch register for use inside the asm code:
241
252
242
253
```rust
254
+
# #![feature(asm)]
243
255
// Multiply x by 6 using shifts and adds
244
256
letmutx:u64=4;
245
257
unsafe {
@@ -259,14 +271,15 @@ A special operand type, `sym`, allows you to use the symbol name of a `fn` or `s
259
271
This allows you to call a function or access a global variable without needing to keep its address in a register.
260
272
261
273
```rust
274
+
# #![feature(asm)]
262
275
extern"C"fnfoo(arg:i32) {
263
276
println!("arg = {}", arg);
264
277
}
265
278
266
279
fncall_foo(arg:i32) {
267
280
unsafe {
268
281
asm!(
269
-
"call {}"
282
+
"call {}",
270
283
symfoo,
271
284
// 1st argument in rdi, which is caller-saved
272
285
inout("rdi") arg=>_,
@@ -294,10 +307,11 @@ By default the compiler will always choose the name that refers to the full regi
294
307
This default can be overriden by using modifiers on the template string operands, just like you would with format strings:
295
308
296
309
```rust
310
+
# #![feature(asm)]
297
311
letmutx:u16=0xab;
298
312
299
313
unsafe {
300
-
asm!("mov {0:h}, {0:b}", inout(reg_abcd) x);
314
+
asm!("mov {0:h}, {0:l}", inout(reg_abcd) x);
301
315
}
302
316
303
317
assert_eq!(x, 0xabab);
@@ -306,7 +320,7 @@ assert_eq!(x, 0xabab);
306
320
In this example, we use the `reg_abcd` register class to restrict the register allocator to the 4 legacy x86 register (`ax`, `bx`, `cx`, `dx`) of which the first two bytes can be addressed independently.
307
321
308
322
Let us assume that the register allocator has chosen to allocate `x` in the `ax` register.
309
-
The `h` modifier will emit the register name for the high byte of that register and the `b` modifier will emit the register name for the low byte. The asm code will therefore be expanded as `mov ah, al` which copies the low byte of the value into the high byte.
323
+
The `h` modifier will emit the register name for the high byte of that register and the `l` modifier will emit the register name for the low byte. The asm code will therefore be expanded as `mov ah, al` which copies the low byte of the value into the high byte.
310
324
311
325
If you use a smaller data type (e.g. `u16`) with an operand and forget the use template modifiers, the compiler will emit a warning and suggest the correct modifier to use.
312
326
@@ -317,6 +331,7 @@ By default, an inline assembly block is treated the same way as an external FFI
317
331
Let's take our previous example of an `add` instruction:
318
332
319
333
```rust
334
+
# #![feature(asm)]
320
335
letmuta:u64=4;
321
336
letb:u64=4;
322
337
unsafe {
@@ -348,7 +363,7 @@ When required, options are specified as the final argument.
@@ -612,7 +627,7 @@ Currently the following options are defined:
612
627
-`pure`: The `asm` block has no side effects, and its outputs depend only on its direct inputs (i.e. the values themselves, not what they point to) or values read from memory (unless the `nomem` options is also set). This allows the compiler to execute the `asm` block fewer times than specified in the program (e.g. by hoisting it out of a loop) or even eliminate it entirely if the outputs are not used.
613
628
-`nomem`: The `asm` blocks does not read or write to any memory. This allows the compiler to cache the values of modified global variables in registers across the `asm` block since it knows that they are not read or written to by the `asm`.
614
629
-`readonly`: The `asm` block does not write to any memory. This allows the compiler to cache the values of unmodified global variables in registers across the `asm` block since it knows that they are not written to by the `asm`.
615
-
-`preserves_flags`: The `asm` block does not modify the flags register (defined in the [rules][rules] below). This allows the compiler to avoid recomputing the condition flags after the `asm` block.
630
+
-`preserves_flags`: The `asm` block does not modify the flags register (defined in the rules below). This allows the compiler to avoid recomputing the condition flags after the `asm` block.
616
631
-`noreturn`: The `asm` block never returns, and its return type is defined as `!` (never). Behavior is undefined if execution falls through past the end of the asm code. A `noreturn` asm block behaves just like a function which doesn't return; notably, local variables in scope are not dropped before it is invoked.
617
632
-`nostack`: The `asm` block does not push data to the stack, or write to the stack red-zone (if supported by the target). If this option is *not* used then the stack pointer is guaranteed to be suitably aligned (according to the target ABI) for a function call.
618
633
-`att_syntax`: This option is only valid on x86, and causes the assembler to use the `.att_syntax prefix` mode of the GNU assembler. Register operands are substituted in with a leading `%`.
@@ -624,7 +639,6 @@ The compiler performs some additional checks on options:
624
639
- It is a compile-time error to specify `noreturn` on an asm block with outputs.
625
640
626
641
## Rules for inline assembly
627
-
[rules]: #rules
628
642
629
643
- Any registers not specified as inputs will contain an undefined value on entry to the asm block.
630
644
- An "undefined value" in the context of inline assembly means that the register can (non-deterministically) have any one of the possible values allowed by the architecture. Notably it is not the same as an LLVM `undef` which can have a different value every time you read it (since such a concept does not exist in assembly code).
0 commit comments