|
2 | 2 | # Inline assembly
|
3 | 3 |
|
4 | 4 | r[asm.intro]
|
5 |
| -Support for inline assembly is provided via the [`asm!`] and [`global_asm!`] macros. |
| 5 | +Support for inline assembly is provided via the [`asm!`], [`naked_asm!`] and [`global_asm!`] macros. |
6 | 6 | It can be used to embed handwritten assembly in the assembly output generated by the compiler.
|
7 | 7 |
|
8 | 8 | [`asm!`]: core::arch::asm
|
| 9 | +[`naked_asm!`]: core::arch::naked_asm |
9 | 10 | [`global_asm!`]: core::arch::global_asm
|
10 | 11 |
|
11 | 12 | r[asm.stable-targets]
|
@@ -60,20 +61,25 @@ option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nost
|
60 | 61 | options := "options(" option *("," option) [","] ")"
|
61 | 62 | operand := reg_operand / clobber_abi / options
|
62 | 63 | asm := "asm!(" format_string *("," format_string) *("," operand) [","] ")"
|
| 64 | +naked_asm := "asm!(" format_string *("," format_string) *("," operand) [","] ")" |
63 | 65 | global_asm := "global_asm!(" format_string *("," format_string) *("," operand) [","] ")"
|
64 | 66 | ```
|
65 | 67 |
|
66 | 68 | r[asm.scope]
|
67 | 69 | ## Scope
|
68 | 70 |
|
69 | 71 | r[asm.scope.intro]
|
70 |
| -Inline assembly can be used in one of two ways. |
| 72 | +Inline assembly can be used in one of three ways. |
71 | 73 |
|
72 | 74 | r[asm.scope.asm]
|
73 | 75 | With the `asm!` macro, the assembly code is emitted in a function scope and integrated into the compiler-generated assembly code of a function.
|
74 | 76 | This assembly code must obey [strict rules](#rules-for-inline-assembly) to avoid undefined behavior.
|
75 | 77 | Note that in some cases the compiler may choose to emit the assembly code as a separate function and generate a call to it.
|
76 | 78 |
|
| 79 | +r[asm.scope.naked_asm] |
| 80 | +With the `naked_asm!` macro, the assembly code is emitted in a function scope and constitutes the full assembly code of a function. |
| 81 | +The `naked_asm!` macro is only allowed in [naked functions](../attributes/codegen.md#the-naked-attribute). |
| 82 | + |
77 | 83 | r[asm.scope.global_asm]
|
78 | 84 | With the `global_asm!` macro, the assembly code is emitted in a global scope, outside a function.
|
79 | 85 | 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.
|
@@ -181,8 +187,11 @@ Operand expressions are evaluated from left to right, just like function call ar
|
181 | 187 | After the `asm!` has executed, outputs are written to in left to right order.
|
182 | 188 | This is significant if two outputs point to the same place: that place will contain the value of the rightmost output.
|
183 | 189 |
|
| 190 | +r[asm.operand-type.naked_asm-restriction] |
| 191 | +Because `naked_asm!` defines a whole function body, it can only use `sym` and `const` operands. |
| 192 | + |
184 | 193 | r[asm.operand-type.global_asm-restriction]
|
185 |
| -Since `global_asm!` exists outside a function, it can only use `sym` and `const` operands. |
| 194 | +Because `global_asm!` exists outside a function, it can only use `sym` and `const` operands. |
186 | 195 |
|
187 | 196 | r[asm.register-operands]
|
188 | 197 | ## Register operands
|
@@ -571,9 +580,13 @@ r[asm.options.checks.pure]
|
571 | 580 | r[asm.options.checks.noreturn]
|
572 | 581 | - It is a compile-time error to specify `noreturn` on an asm block with outputs.
|
573 | 582 |
|
| 583 | +r[asm.options.naked_asm-restriction] |
| 584 | +`global_asm!` only supports the `att_syntax` and `raw` options. |
| 585 | +The remaining options are not meaningful because the inline assembly defines the whole function body. |
| 586 | + |
574 | 587 | r[asm.options.global_asm-restriction]
|
575 | 588 | `global_asm!` only supports the `att_syntax` and `raw` options.
|
576 |
| -The remaining options are not meaningful for global-scope inline assembly |
| 589 | +The remaining options are not meaningful for global-scope inline assembly. |
577 | 590 |
|
578 | 591 | r[asm.rules]
|
579 | 592 | ## Rules for inline assembly
|
@@ -685,6 +698,43 @@ r[asm.rules.x86-prefix-restriction]
|
685 | 698 | r[asm.rules.preserves_flags]
|
686 | 699 | > **Note**: As a general rule, the flags covered by `preserves_flags` are those which are *not* preserved when performing a function call.
|
687 | 700 |
|
| 701 | +r[asm.naked-rules] |
| 702 | +## Rules for naked inline assembly |
| 703 | + |
| 704 | +r[asm.naked-rules.intro] |
| 705 | +To avoid undefined behavior, these rules must be followed when using function-scope inline assembly in naked functions (`naked_asm!`): |
| 706 | + |
| 707 | +r[asm.naked-rules.reg-not-input] |
| 708 | +- Any registers not used for function inputs according to the calling convention and function signature will contain an undefined value on entry to the asm block. |
| 709 | + - 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. |
| 710 | + 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). |
| 711 | + |
| 712 | +r[asm.naked-rules.reg-not-output] |
| 713 | +- Any callee-saved registers must have the same value upon exiting the asm block as they had on entry, otherwise behavior is undefined. |
| 714 | + - Caller-saved registes may be used freely, even if they are not used for the return value. |
| 715 | + |
| 716 | +r[asm.naked-rules.unwind] |
| 717 | +- Behavior is undefined if execution unwinds out of an asm block. |
| 718 | + - This also applies if the assembly code calls a function which then unwinds. |
| 719 | + |
| 720 | +r[asm.naked-rules.noreturn] |
| 721 | +- Behavior is undefined if execution falls through to the end of the asm block. |
| 722 | + |
| 723 | +r[asm.naked-rules.mem-same-as-ffi] |
| 724 | +- The set of memory locations that assembly code is allowed to read and write are the same as those allowed for an FFI function. |
| 725 | + - Refer to the unsafe code guidelines for the exact rules. |
| 726 | + - These rules do not apply to memory which is private to the asm code, such as stack space allocated within the asm block. |
| 727 | + |
| 728 | +r[asm.naked-rules.black-box] |
| 729 | +- The compiler cannot assume that the instructions in the asm are the ones that will actually end up executed. |
| 730 | + - This effectively means that the compiler must treat the `naked_asm!` as a black box and only take the interface specification into account, not the instructions themselves. |
| 731 | + - Runtime code patching is allowed, via target-specific mechanisms. |
| 732 | + - However there is no guarantee that each `naked_asm!` directly corresponds to a single instance of instructions in the object file: the compiler is free to duplicate or deduplicate `naked_asm!` blocks. |
| 733 | + |
| 734 | +r[asm.naked-rules.not-exactly-once] |
| 735 | +- You cannot assume that an `naked_asm!` block will appear exactly once in the output binary. |
| 736 | + The compiler is allowed to instantiate multiple copies of the `naked_asm!` block, for example when the function containing it is inlined in multiple places. |
| 737 | + |
688 | 738 | r[asm.validity]
|
689 | 739 | ### Correctness and Validity
|
690 | 740 |
|
|
0 commit comments