Skip to content

Commit 6f8be8c

Browse files
committed
Fix docs
1 parent 9215ead commit 6f8be8c

File tree

1 file changed

+27
-13
lines changed
  • src/doc/unstable-book/src/library-features

1 file changed

+27
-13
lines changed

src/doc/unstable-book/src/library-features/asm.md

+27-13
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ cannot be otherwise achieved. Accessing low level hardware primitives, e.g. in k
2525
Let us start with the simplest possible example:
2626

2727
```rust
28+
# #![feature(asm)]
2829
unsafe {
2930
asm!("nop");
3031
}
@@ -41,6 +42,7 @@ Now inserting an instruction that does nothing is rather boring. Let us do somet
4142
actually acts on data:
4243

4344
```rust
45+
# #![feature(asm)]
4446
let x: u64;
4547
unsafe {
4648
asm!("mov {}, 5", out(reg) x);
@@ -62,6 +64,7 @@ the template and will read the variable from there after the inline assembly fin
6264
Let us see another example that also uses an input:
6365

6466
```rust
67+
# #![feature(asm)]
6568
let i: u64 = 3;
6669
let o: u64;
6770
unsafe {
@@ -93,6 +96,7 @@ readability, and allows reordering instructions without changing the argument or
9396
We can further refine the above example to avoid the `mov` instruction:
9497

9598
```rust
99+
# #![feature(asm)]
96100
let mut x: u64 = 3;
97101
unsafe {
98102
asm!("add {0}, {number}", inout(reg) x, number = const 5);
@@ -106,6 +110,7 @@ This is different from specifying an input and output separately in that it is g
106110
It is also possible to specify different variables for the input and output parts of an `inout` operand:
107111

108112
```rust
113+
# #![feature(asm)]
109114
let x: u64 = 3;
110115
let y: u64;
111116
unsafe {
@@ -127,6 +132,7 @@ There is also a `inlateout` variant of this specifier.
127132
Here is an example where `inlateout` *cannot* be used:
128133

129134
```rust
135+
# #![feature(asm)]
130136
let mut a: u64 = 4;
131137
let b: u64 = 4;
132138
let c: u64 = 4;
@@ -144,6 +150,7 @@ Here the compiler is free to allocate the same register for inputs `b` and `c` s
144150
However the following example can use `inlateout` since the output is only modified after all input registers have been read:
145151

146152
```rust
153+
# #![feature(asm)]
147154
let mut a: u64 = 4;
148155
let b: u64 = 4;
149156
unsafe {
@@ -161,21 +168,24 @@ Therefore, Rust inline assembly provides some more specific constraint specifier
161168
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`
162169
among others can be addressed by their name.
163170

164-
```rust
171+
```rust,no_run
172+
# #![feature(asm)]
173+
let cmd = 0xd1;
165174
unsafe {
166-
asm!("out 0x64, rax", in("rax") cmd);
175+
asm!("out 0x64, eax", in("eax") cmd);
167176
}
168177
```
169178

170179
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.
173182

174183
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.
175184

176185
Consider this example which uses the x86 `mul` instruction:
177186

178187
```rust
188+
# #![feature(asm)]
179189
fn mul(a: u64, b: u64) -> u128 {
180190
let lo: u64;
181191
let hi: u64;
@@ -191,7 +201,7 @@ fn mul(a: u64, b: u64) -> u128 {
191201
);
192202
}
193203

194-
hi as u128 << 64 + lo as u128
204+
(hi as u128) << 64 + lo as u128
195205
}
196206
```
197207

@@ -211,8 +221,9 @@ We need to tell the compiler about this since it may need to save and restore th
211221
around the inline assembly block.
212222

213223
```rust
214-
let ebx: u64;
215-
let ecx: u64;
224+
# #![feature(asm)]
225+
let ebx: u32;
226+
let ecx: u32;
216227

217228
unsafe {
218229
asm!(
@@ -240,6 +251,7 @@ However we still need to tell the compiler that `eax` and `edx` have been modifi
240251
This can also be used with a general register class (e.g. `reg`) to obtain a scratch register for use inside the asm code:
241252

242253
```rust
254+
# #![feature(asm)]
243255
// Multiply x by 6 using shifts and adds
244256
let mut x: u64 = 4;
245257
unsafe {
@@ -259,14 +271,15 @@ A special operand type, `sym`, allows you to use the symbol name of a `fn` or `s
259271
This allows you to call a function or access a global variable without needing to keep its address in a register.
260272

261273
```rust
274+
# #![feature(asm)]
262275
extern "C" fn foo(arg: i32) {
263276
println!("arg = {}", arg);
264277
}
265278

266279
fn call_foo(arg: i32) {
267280
unsafe {
268281
asm!(
269-
"call {}"
282+
"call {}",
270283
sym foo,
271284
// 1st argument in rdi, which is caller-saved
272285
inout("rdi") arg => _,
@@ -294,10 +307,11 @@ By default the compiler will always choose the name that refers to the full regi
294307
This default can be overriden by using modifiers on the template string operands, just like you would with format strings:
295308

296309
```rust
310+
# #![feature(asm)]
297311
let mut x: u16 = 0xab;
298312

299313
unsafe {
300-
asm!("mov {0:h}, {0:b}", inout(reg_abcd) x);
314+
asm!("mov {0:h}, {0:l}", inout(reg_abcd) x);
301315
}
302316

303317
assert_eq!(x, 0xabab);
@@ -306,7 +320,7 @@ assert_eq!(x, 0xabab);
306320
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.
307321

308322
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.
310324

311325
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.
312326

@@ -317,6 +331,7 @@ By default, an inline assembly block is treated the same way as an external FFI
317331
Let's take our previous example of an `add` instruction:
318332

319333
```rust
334+
# #![feature(asm)]
320335
let mut a: u64 = 4;
321336
let b: u64 = 4;
322337
unsafe {
@@ -348,7 +363,7 @@ When required, options are specified as the final argument.
348363

349364
The following ABNF specifies the general syntax:
350365

351-
```
366+
```ignore
352367
dir_spec := "in" / "out" / "lateout" / "inout" / "inlateout"
353368
reg_spec := <register class> / "<explicit register>"
354369
operand_expr := expr / "_" / expr "=>" expr / expr "=>" "_"
@@ -612,7 +627,7 @@ Currently the following options are defined:
612627
- `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.
613628
- `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`.
614629
- `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.
616631
- `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.
617632
- `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.
618633
- `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:
624639
- It is a compile-time error to specify `noreturn` on an asm block with outputs.
625640

626641
## Rules for inline assembly
627-
[rules]: #rules
628642

629643
- Any registers not specified as inputs will contain an undefined value on entry to the asm block.
630644
- 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

Comments
 (0)