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
Reformat (and only reformat) the inline assembly chapter
The go forward plan adopted by T-spec on 2024-06-13 includes, as one
step, to reformat all of the chapters of the Reference to attach named
identifiers to each claim, more or less. The resulting text will use
the `mdbook-spec` extension for rendering (see PR #1542).
Adding these named identifiers more granularly throughout the document
is one step in allowing the Reference to be used as a specification
for Rust in safety-critical applications.
Per our plan, we want to reformat one chapter first, to ensure our
happiness with that and to perfect our process, and to then
reformat (and review and merge those reformattings of) all of the rest
of the Reference chapters in the same way. We discussed and imagined
that this reformatting would be somewhat mechanical, and that it could
be done by a technical writer with limited experience with Rust. This
is what gave us confidence that this work could be hired out,
completed, and reviewed on the months-scale timeline that we had set
out.
As a demonstration of the first step in that plan, this PR
performs *only* reformatting. That is, we add identifiers to each
claim, more or less, *and nothing else*. We change *none* of the
verbiage in this chapter.
Our finding is that doing things this way works out fine. The
original text was already organized reasonably well enough to just
leave it in place and add the identifiers.
There's always more that could be done to improve a chapter. E.g.,
perhaps some claims could be broken down further still and more
identifiers added, though there is a distinct readability tradeoff
here. We've tried to strike a reasonable balance in this PR.
The point of the exercise contained in this PR is that this diff is
straightforward to review and moves us in the direction that we want
to go. We can always make other changes later, and by separating them
out, those changes will be easier to review also.
Note that we're unhappy with the current rendering when two
identifiers need to be stacked, e.g.:
```
[asm]
[asm.intro]
```
We'll plan to improve this later and separately with work in
`mdbook-spec` or in the style sheets.
With the `asm!` macro, the assembly code is emitted in a function scope and integrated into the compiler-generated assembly code of a function.
63
75
This assembly code must obey [strict rules](#rules-for-inline-assembly) to avoid undefined behavior.
64
76
Note that in some cases the compiler may choose to emit the assembly code as a separate function and generate a call to it.
65
77
78
+
r[asm.scope.global_asm]
66
79
With the `global_asm!` macro, the assembly code is emitted in a global scope, outside a function.
67
80
This can be used to hand-write entire functions using assembly code, and generally provides much more freedom to use arbitrary registers and assembler directives.
68
81
69
82
## Template string arguments
70
83
84
+
r[asm.ts-args]
85
+
86
+
r[asm.ts-args.syntax]
71
87
The assembler template uses the same syntax as [format strings][format-syntax] (i.e. placeholders are specified by curly braces).
88
+
89
+
r[asm.ts-args.order]
72
90
The corresponding arguments are accessed in order, by index, or by name.
91
+
92
+
r[asm.ts-args.no-implicit]
73
93
However, implicit named arguments (introduced by [RFC #2795][rfc-2795]) are not supported.
74
94
95
+
r[asm.ts-args.one-or-more]
75
96
An `asm!` invocation may have one or more template string arguments; an `asm!` with multiple template string arguments is treated as if all the strings were concatenated with a `\n` between them.
76
97
The expected usage is for each template string argument to correspond to a line of assembly code.
98
+
99
+
r[asm.ts-args.before-other-args]
77
100
All template string arguments must appear before any other arguments.
78
101
102
+
r[asm.ts-args.positional-first]
79
103
As with format strings, positional arguments must appear before named arguments and explicit [register operands](#register-operands).
80
104
105
+
r[asm.ts-args.register-operands]
81
106
Explicit register operands cannot be used by placeholders in the template string.
107
+
108
+
r[asm.ts-args.at-least-once]
82
109
All other named and positional operands must appear at least once in the template string, otherwise a compiler error is generated.
83
110
111
+
r[asm.ts-args.opaque]
84
112
The exact assembly code syntax is target-specific and opaque to the compiler except for the way operands are substituted into the template string to form the code passed to the assembler.
85
113
114
+
r[asm.ts-args.llvm-syntax]
86
115
Currently, all supported targets follow the assembly code syntax used by LLVM's internal assembler which usually corresponds to that of the GNU assembler (GAS).
87
116
On x86, the `.intel_syntax noprefix` mode of GAS is used by default.
88
117
On ARM, the `.syntax unified` mode is used.
@@ -95,56 +124,83 @@ Further constraints on the directives used by inline assembly are indicated by [
95
124
96
125
## Operand type
97
126
127
+
r[asm.operand-type]
128
+
129
+
r[asm.operand-type.supported-operands]
98
130
Several types of operands are supported:
99
131
132
+
r[asm.operand-type.supported-operands.in]
100
133
*`in(<reg>) <expr>`
101
134
-`<reg>` can refer to a register class or an explicit register.
102
135
The allocated register name is substituted into the asm template string.
103
136
- The allocated register will contain the value of `<expr>` at the start of the asm code.
104
137
- The allocated register must contain the same value at the end of the asm code (except if a `lateout` is allocated to the same register).
138
+
139
+
r[asm.operand-type.supported-operands.out]
105
140
*`out(<reg>) <expr>`
106
141
-`<reg>` can refer to a register class or an explicit register.
107
142
The allocated register name is substituted into the asm template string.
108
143
- The allocated register will contain an undefined value at the start of the asm code.
109
144
-`<expr>` must be a (possibly uninitialized) place expression, to which the contents of the allocated register are written at the end of the asm code.
110
145
- An underscore (`_`) may be specified instead of an expression, which will cause the contents of the register to be discarded at the end of the asm code (effectively acting as a clobber).
146
+
147
+
r[asm.operand-type.supported-operands.lateout]
111
148
*`lateout(<reg>) <expr>`
112
149
- Identical to `out` except that the register allocator can reuse a register allocated to an `in`.
113
150
- You should only write to the register after all inputs are read, otherwise you may clobber an input.
151
+
152
+
r[asm.operand-type.supported-operands.inout]
114
153
*`inout(<reg>) <expr>`
115
154
-`<reg>` can refer to a register class or an explicit register.
116
155
The allocated register name is substituted into the asm template string.
117
156
- The allocated register will contain the value of `<expr>` at the start of the asm code.
118
157
-`<expr>` must be a mutable initialized place expression, to which the contents of the allocated register are written at the end of the asm code.
- Same as `inout` except that the initial value of the register is taken from the value of `<in expr>`.
121
162
-`<out expr>` must be a (possibly uninitialized) place expression, to which the contents of the allocated register are written at the end of the asm code.
122
163
- An underscore (`_`) may be specified instead of an expression for `<out expr>`, which will cause the contents of the register to be discarded at the end of the asm code (effectively acting as a clobber).
123
164
-`<in expr>` and `<out expr>` may have different types.
- Identical to `inout` except that the register allocator can reuse a register allocated to an `in` (this can happen if the compiler knows the `in` has the same initial value as the `inlateout`).
126
169
- You should only write to the register after all inputs are read, otherwise you may clobber an input.
170
+
171
+
r[asm.operand-type.supported-operands.sym]
127
172
*`sym <path>`
128
173
-`<path>` must refer to a `fn` or `static`.
129
174
- A mangled symbol name referring to the item is substituted into the asm template string.
130
175
- The substituted string does not include any modifiers (e.g. GOT, PLT, relocations, etc).
131
176
-`<path>` is allowed to point to a `#[thread_local]` static, in which case the asm code can combine the symbol with relocations (e.g. `@plt`, `@TPOFF`) to read from thread-local data.
132
177
178
+
r[asm.operand-type.left-to-right]
133
179
Operand expressions are evaluated from left to right, just like function call arguments.
134
180
After the `asm!` has executed, outputs are written to in left to right order.
135
181
This is significant if two outputs point to the same place: that place will contain the value of the rightmost output.
136
182
183
+
r[asm.operand-type.global_asm-restriction]
137
184
Since `global_asm!` exists outside a function, it can only use `sym` operands.
138
185
139
186
## Register operands
140
187
188
+
r[asm.register-operands]
189
+
190
+
r[asm.register-operands.register-or-class]
141
191
Input and output operands can be specified either as an explicit register or as a register class from which the register allocator can select a register.
142
192
Explicit registers are specified as string literals (e.g. `"eax"`) while register classes are specified as identifiers (e.g. `reg`).
Note that explicit registers treat register aliases (e.g. `r14` vs `lr` on ARM) and smaller views of a register (e.g. `eax` vs `rax`) as equivalent to the base register.
196
+
197
+
r[asm.register-operands.error-two-operands]
145
198
It is a compile-time error to use the same explicit register for two input operands or two output operands.
199
+
200
+
r[asm.register-operands.error-overlapping]
146
201
Additionally, it is also a compile-time error to use overlapping registers (e.g. ARM VFP) in input operands or in output operands.
147
202
203
+
r[asm.register-operands.allowed-types]
148
204
Only the following types are allowed as operands for inline assembly:
149
205
- Integers (signed and unsigned)
150
206
- Floating-point numbers
@@ -153,6 +209,7 @@ Only the following types are allowed as operands for inline assembly:
153
209
- SIMD vectors (structs defined with `#[repr(simd)]` and which implement `Copy`).
154
210
This includes architecture-specific vector types defined in `std::arch` such as `__m128` (x86) or `int8x16_t` (ARM).
@@ -191,11 +248,10 @@ Here is the list of currently supported register classes:
191
248
192
249
> **Notes**:
193
250
> - On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register.
194
-
>
195
251
> - On x86-64 the high byte registers (e.g. `ah`) are not available in the `reg_byte` register class.
196
-
>
197
252
> - Some register classes are marked as "Only clobbers" which means that registers in these classes cannot be used for inputs or outputs, only clobbers of the form `out(<explicit register>) _` or `lateout(<explicit register>) _`.
198
253
254
+
r[asm.register-operands.value-type-constraints]
199
255
Each register class has constraints on which value types they can be used with.
200
256
This is necessary because the way a value is loaded into a register depends on its type.
201
257
For example, on big-endian systems, loading a `i32x4` and a `i8x16` into a SIMD register may result in different register contents even if the byte-wise memory representation of both values is identical.
@@ -231,15 +287,20 @@ The availability of supported types for a particular register class may depend o
231
287
232
288
> **Note**: For the purposes of the above table pointers, function pointers and `isize`/`usize` are treated as the equivalent integer type (`i16`/`i32`/`i64` depending on the target).
233
289
290
+
r[asm.register-operands.smaller-value]
234
291
If a value is of a smaller size than the register it is allocated in then the upper bits of that register will have an undefined value for inputs and will be ignored for outputs.
235
292
The only exception is the `freg` register class on RISC-V where `f32` values are NaN-boxed in a `f64` as required by the RISC-V architecture.
236
293
294
+
r[asm.register-operands.separate-input-output]
237
295
When separate input and output expressions are specified for an `inout` operand, both expressions must have the same type.
238
296
The only exception is if both operands are pointers or integers, in which case they are only required to have the same size.
239
297
This restriction exists because the register allocators in LLVM and GCC sometimes cannot handle tied operands with different types.
240
298
241
299
## Register names
242
300
301
+
r[asm.register-names]
302
+
303
+
r[asm.register-names.supported-register-aliases]
243
304
Some registers have multiple names.
244
305
These are all treated by the compiler as identical to the base register name.
245
306
Here is the list of all supported register aliases:
@@ -302,6 +363,7 @@ Here is the list of all supported register aliases:
302
363
| LoongArch |`$f[8-23]`|`$ft[0-15]`|
303
364
| LoongArch |`$f[24-31]`|`$fs[0-7]`|
304
365
366
+
r[asm.register-names.not-for-io]
305
367
Some registers cannot be used for input or output operands:
306
368
307
369
| Architecture | Unsupported register | Reason |
@@ -321,14 +383,21 @@ Some registers cannot be used for input or output operands:
321
383
| LoongArch |`$r2` or `$tp`| This is reserved for TLS. |
322
384
| LoongArch |`$r21`| This is reserved by the ABI. |
323
385
386
+
r[asm.register-names.fp-bp-reserved]
324
387
The frame pointer and base pointer registers are reserved for internal use by LLVM. While `asm!` statements cannot explicitly specify the use of reserved registers, in some cases LLVM will allocate one of these reserved registers for `reg` operands. Assembly code making use of reserved registers should be careful since `reg` operands may use the same registers.
325
388
326
389
## Template modifiers
327
390
391
+
r[asm.template-modifiers]
392
+
393
+
r[asm.template-modifiers.intro]
328
394
The placeholders can be augmented by modifiers which are specified after the `:` in the curly braces.
329
395
These modifiers do not affect register allocation, but change the way operands are formatted when inserted into the template string.
396
+
397
+
r[asm.template-modifiers.only-one]
330
398
Only one modifier is allowed per template placeholder.
331
399
400
+
r[asm.template-modifiers.supported-modifiers]
332
401
The supported modifiers are a subset of LLVM's (and GCC's) [asm template argument modifiers][llvm-argmod], but do not use the same letter codes.
333
402
334
403
| Architecture | Register class | Modifier | Example output | LLVM modifier |
@@ -375,6 +444,7 @@ The supported modifiers are a subset of LLVM's (and GCC's) [asm template argumen
375
444
> GCC will infer the modifier based on the operand value type, while we default to the full register size.
376
445
> - on x86 `xmm_reg`: the `x`, `t` and `g` LLVM modifiers are not yet implemented in LLVM (they are supported by GCC only), but this should be a simple change.
377
446
447
+
r[asm.template-modifiers.smaller-value]
378
448
As stated in the previous section, passing an input value smaller than the register width will result in the upper bits of the register containing undefined values.
379
449
This is not a problem if the inline asm only accesses the lower bits of the register, which can be done by using a template modifier to use a subregister name in the asm code (e.g. `ax` instead of `rax`).
380
450
Since this an easy pitfall, the compiler will suggest a template modifier to use where appropriate given the input type.
@@ -384,13 +454,22 @@ If all references to an operand already have modifiers then the warning is suppr
384
454
385
455
## ABI clobbers
386
456
457
+
r[asm.abi-clobbers]
458
+
459
+
r[asm.abi-clobbers.intro]
387
460
The `clobber_abi` keyword can be used to apply a default set of clobbers to an `asm!` block.
388
461
This will automatically insert the necessary clobber constraints as needed for calling a function with a particular calling convention: if the calling convention does not fully preserve the value of a register across a call then `lateout("...") _` is implicitly added to the operands list (where the `...` is replaced by the register's name).
389
462
463
+
r[asm.abi-clobbers.many]
390
464
`clobber_abi` may be specified any number of times. It will insert a clobber for all unique registers in the union of all specified calling conventions.
391
465
466
+
r[asm.abi-clobbers.must-specify]
392
467
Generic register class outputs are disallowed by the compiler when `clobber_abi` is used: all outputs must specify an explicit register.
468
+
469
+
r[asm.abi-clobbers.explicit-have-precedence]
393
470
Explicit register outputs have precedence over the implicit clobbers inserted by `clobber_abi`: a clobber will only be inserted for a register if that register is not used as an output.
471
+
472
+
r[asm.abi-clobbers.supported-abis]
394
473
The following ABIs can be used with `clobber_abi`:
395
474
396
475
| Architecture | ABI name | Clobbered registers |
@@ -410,70 +489,117 @@ The list of clobbered registers for each ABI is updated in rustc as architecture
410
489
411
490
## Options
412
491
492
+
r[asm.options]
493
+
494
+
r[asm.options.supported-options]
413
495
Flags are used to further influence the behavior of the inline assembly block.
414
496
Currently the following options are defined:
497
+
498
+
r[asm.options.supported-options.pure]
415
499
-`pure`: The `asm!` block has no side effects, must eventually return, 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).
416
500
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.
417
501
The `pure` option must be combined with either the `nomem` or `readonly` options, otherwise a compile-time error is emitted.
502
+
503
+
r[asm.options.supported-options.nomem]
418
504
-`nomem`: The `asm!` blocks does not read or write to any memory.
419
505
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!`.
420
506
The compiler also assumes that this `asm!` block does not perform any kind of synchronization with other threads, e.g. via fences.
507
+
508
+
r[asm.options.supported-options.readonly]
421
509
-`readonly`: The `asm!` block does not write to any memory.
422
510
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!`.
423
511
The compiler also assumes that this `asm!` block does not perform any kind of synchronization with other threads, e.g. via fences.
512
+
513
+
r[asm.options.supported-options.preserves_flags]
424
514
-`preserves_flags`: The `asm!` block does not modify the flags register (defined in the rules below).
425
515
This allows the compiler to avoid recomputing the condition flags after the `asm!` block.
516
+
517
+
r[asm.options.supported-options.noreturn]
426
518
-`noreturn`: The `asm!` block never returns, and its return type is defined as `!` (never).
427
519
Behavior is undefined if execution falls through past the end of the asm code.
428
520
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.
521
+
522
+
r[asm.options.supported-options.nostack]
429
523
-`nostack`: The `asm!` block does not push data to the stack, or write to the stack red-zone (if supported by the target).
430
524
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.
525
+
526
+
r[asm.options.supported-options.att_syntax]
431
527
-`att_syntax`: This option is only valid on x86, and causes the assembler to use the `.att_syntax prefix` mode of the GNU assembler.
432
528
Register operands are substituted in with a leading `%`.
529
+
530
+
r[asm.options.supported-options.raw]
433
531
-`raw`: This causes the template string to be parsed as a raw assembly string, with no special handling for `{` and `}`.
434
532
This is primarily useful when including raw assembly code from an external file using `include_str!`.
435
533
534
+
r[asm.options.checks]
436
535
The compiler performs some additional checks on options:
536
+
537
+
r[asm.options.checks.mutually-exclusive]
437
538
- The `nomem` and `readonly` options are mutually exclusive: it is a compile-time error to specify both.
539
+
540
+
r[asm.options.checks.pure]
438
541
- It is a compile-time error to specify `pure` on an asm block with no outputs or only discarded outputs (`_`).
542
+
543
+
r[asm.options.checks.noreturn]
439
544
- It is a compile-time error to specify `noreturn` on an asm block with outputs.
440
545
546
+
r[asm.options.global_asm-restriction]
441
547
`global_asm!` only supports the `att_syntax` and `raw` options.
442
548
The remaining options are not meaningful for global-scope inline assembly
443
549
444
550
## Rules for inline assembly
445
551
552
+
r[asm.rules]
553
+
554
+
r[asm.rules.intro]
446
555
To avoid undefined behavior, these rules must be followed when using function-scope inline assembly (`asm!`):
447
556
557
+
r[asm.rules.reg-not-input]
448
558
- Any registers not specified as inputs will contain an undefined value on entry to the asm block.
449
559
- 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.
450
560
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).
561
+
562
+
r[asm.rules.reg-not-output]
451
563
- Any registers not specified as outputs must have the same value upon exiting the asm block as they had on entry, otherwise behavior is undefined.
452
564
- This only applies to registers which can be specified as an input or output.
453
565
Other registers follow target-specific rules.
454
566
- Note that a `lateout` may be allocated to the same register as an `in`, in which case this rule does not apply.
455
567
Code should not rely on this however since it depends on the results of register allocation.
568
+
569
+
r[asm.rules.unwind]
456
570
- Behavior is undefined if execution unwinds out of an asm block.
457
571
- This also applies if the assembly code calls a function which then unwinds.
572
+
573
+
r[asm.rules.mem-same-as-ffi]
458
574
- The set of memory locations that assembly code is allowed to read and write are the same as those allowed for an FFI function.
459
575
- Refer to the unsafe code guidelines for the exact rules.
460
576
- If the `readonly` option is set, then only memory reads are allowed.
461
577
- If the `nomem` option is set then no reads or writes to memory are allowed.
462
578
- These rules do not apply to memory which is private to the asm code, such as stack space allocated within the asm block.
579
+
580
+
r[asm.rules.black-box]
463
581
- The compiler cannot assume that the instructions in the asm are the ones that will actually end up executed.
464
582
- This effectively means that the compiler must treat the `asm!` as a black box and only take the interface specification into account, not the instructions themselves.
465
583
- Runtime code patching is allowed, via target-specific mechanisms.
466
584
- However there is no guarantee that each `asm!` directly corresponds to a single instance of instructions in the object file: the compiler is free to duplicate or deduplicate `asm!` blocks.
585
+
586
+
r[asm.rules.stack-below-sp]
467
587
- Unless the `nostack` option is set, asm code is allowed to use stack space below the stack pointer.
468
588
- On entry to the asm block the stack pointer is guaranteed to be suitably aligned (according to the target ABI) for a function call.
469
589
- You are responsible for making sure you don't overflow the stack (e.g. use stack probing to ensure you hit a guard page).
470
590
- You should adjust the stack pointer when allocating stack memory as required by the target ABI.
471
591
- The stack pointer must be restored to its original value before leaving the asm block.
592
+
593
+
r[asm.rules.noreturn]
472
594
- If the `noreturn` option is set then behavior is undefined if execution falls through to the end of the asm block.
595
+
596
+
r[asm.rules.pure]
473
597
- If the `pure` option is set then behavior is undefined if the `asm!` has side-effects other than its direct outputs.
474
598
Behavior is also undefined if two executions of the `asm!` code with the same inputs result in different outputs.
475
599
- When used with the `nomem` option, "inputs" are just the direct inputs of the `asm!`.
476
600
- When used with the `readonly` option, "inputs" comprise the direct inputs of the `asm!` and any memory that the `asm!` block is allowed to read.
601
+
602
+
r[asm.rules.preserved-registers]
477
603
- These flags registers must be restored upon exiting the asm block if the `preserves_flags` option is set:
478
604
- x86
479
605
- Status flags in `EFLAGS` (CF, PF, AF, ZF, SF, OF).
@@ -494,10 +620,16 @@ To avoid undefined behavior, these rules must be followed when using function-sc
494
620
- Vector extension state (`vtype`, `vl`, `vcsr`).
495
621
- LoongArch
496
622
- Floating-point condition flags in `$fcc[0-7]`.
623
+
624
+
r[asm.rules.x86-df]
497
625
- On x86, the direction flag (DF in `EFLAGS`) is clear on entry to an asm block and must be clear on exit.
498
626
- Behavior is undefined if the direction flag is set on exiting an asm block.
627
+
628
+
r[asm.rules.x86-x87]
499
629
- On x86, the x87 floating-point register stack must remain unchanged unless all of the `st([0-7])` registers have been marked as clobbered with `out("st(0)") _, out("st(1)") _, ...`.
500
630
- If all x87 registers are clobbered then the x87 register stack is guaranteed to be empty upon entering an `asm` block. Assembly code must ensure that the x87 register stack is also empty when exiting the asm block.
631
+
632
+
r[asm.rules.only-on-exit]
501
633
- The requirement of restoring the stack pointer and non-output registers to their original value only applies when exiting an `asm!` block.
502
634
- This means that `asm!` blocks that never return (even if not marked `noreturn`) don't need to preserve these registers.
503
635
- When returning to a different `asm!` block than you entered (e.g. for context switching), these registers must contain the value they had upon entering the `asm!` block that you are *exiting*.
@@ -506,16 +638,26 @@ To avoid undefined behavior, these rules must be followed when using function-sc
506
638
- You are responsible for switching any target-specific state (e.g. thread-local storage, stack bounds).
507
639
- You cannot jump from an address in one `asm!` block to an address in another, even within the same function or block, without treating their contexts as potentially different and requiring context switching. You cannot assume that any particular value in those contexts (e.g. current stack pointer or temporary values below the stack pointer) will remain unchanged between the two `asm!` blocks.
508
640
- The set of memory locations that you may access is the intersection of those allowed by the `asm!` blocks you entered and exited.
641
+
642
+
r[asm.rules.not-successive]
509
643
- You cannot assume that two `asm!` blocks adjacent in source code, even without any other code between them, will end up in successive addresses in the binary without any other instructions between them.
644
+
645
+
r[asm.rules.not-exactly-once]
510
646
- You cannot assume that an `asm!` block will appear exactly once in the output binary.
511
647
The compiler is allowed to instantiate multiple copies of the `asm!` block, for example when the function containing it is inlined in multiple places.
648
+
649
+
r[asm.rules.x86-prefix-restriction]
512
650
- On x86, inline assembly must not end with an instruction prefix (such as `LOCK`) that would apply to instructions generated by the compiler.
513
651
- The compiler is currently unable to detect this due to the way inline assembly is compiled, but may catch and reject this in the future.
514
652
653
+
r[asm.rules.preserves_flags]
515
654
> **Note**: As a general rule, the flags covered by `preserves_flags` are those which are *not* preserved when performing a function call.
516
655
517
656
### Correctness and Validity
518
657
658
+
r[asm.validity]
659
+
660
+
r[asm.validity.necessary-but-not-sufficient]
519
661
In addition to all of the previous rules, the string argument to `asm!` must ultimately become---
520
662
after all other arguments are evaluated, formatting is performed, and operands are translated---
521
663
assembly that is both syntactically correct and semantically valid for the target architecture.
@@ -529,6 +671,7 @@ both correct and valid. For instance:
529
671
- an architecturally unspecified instruction may be assembled into unspecified code
530
672
- a set of instructions, each correct and valid, may cause undefined behavior if placed in immediate succession
531
673
674
+
r[asm.validity.non-exhaustive]
532
675
As a result, these rules are _non-exhaustive_. The compiler is not required to check the
533
676
correctness and validity of the initial string nor the final assembly that is generated.
534
677
The assembler may check for correctness and validity but is not required to do so.
@@ -539,11 +682,16 @@ assuming the responsibility of not violating rules of both the compiler or the a
539
682
540
683
### Directives Support
541
684
685
+
r[asm.directives]
686
+
687
+
r[asm.directives.subset-supported]
542
688
Inline assembly supports a subset of the directives supported by both GNU AS and LLVM's internal assembler, given as follows.
543
689
The result of using other directives is assembler-specific (and may cause an error, or may be accepted as-is).
544
690
691
+
r[asm.directives.stateful]
545
692
If inline assembly includes any "stateful" directive that modifies how subsequent assembly is processed, the block must undo the effects of any such directives before the inline assembly ends.
546
693
694
+
r[asm.directives.supported-directives]
547
695
The following directives are guaranteed to be supported by the assembler:
548
696
549
697
-`.2byte`
@@ -599,8 +747,11 @@ The following directives are guaranteed to be supported by the assembler:
599
747
600
748
#### Target Specific Directive Support
601
749
750
+
r[asm.target-specific-directives]
751
+
602
752
##### Dwarf Unwinding
603
753
754
+
r[asm.target-specific-directives.dwarf-unwinding]
604
755
The following directives are supported on ELF targets that support DWARF unwind info:
605
756
606
757
@@ -629,6 +780,7 @@ The following directives are supported on ELF targets that support DWARF unwind
0 commit comments