Skip to content

Commit b991adf

Browse files
committed
document naked_asm!
1 parent aaef383 commit b991adf

File tree

2 files changed

+56
-6
lines changed

2 files changed

+56
-6
lines changed

src/attributes/codegen.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ No function prologue or epilogue are generated for the attributed function: the
6767
of the `naked_asm!` invocation make up the full body of a naked function.
6868

6969
r[attributes.codegen.naked.call-stack]
70-
The caller must set up the call stack acording to the specified calling convention before
70+
The caller must set up the call stack according to the specified calling convention before
7171
executing a naked function, even in contexts where setting up the call stack would ordinarily
7272
be unnecessary, such as when the function is inlined.
7373

@@ -86,7 +86,7 @@ to the specified calling convention imposes additional safety invariants on its
8686
and therefore must be marked as an [unsafe function].
8787

8888
> ***Note***: a `naked_asm!` invocation may refer to registers that were not specified as operands.
89-
> for standard `asm!` this is undefined behavior, but `inline_asm!` may rely on the state of registers
89+
> for standard `asm!` this is undefined behavior, but `naked_asm!` may rely on the state of registers
9090
> as specified by the calling convention.
9191
9292
r[attributes.codegen.naked.unused-variables]

src/inline-assembly.md

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ r[asm]
22
# Inline assembly
33

44
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.
66
It can be used to embed handwritten assembly in the assembly output generated by the compiler.
77

88
[`asm!`]: core::arch::asm
9+
[`naked_asm!`]: core::arch::naked_asm
910
[`global_asm!`]: core::arch::global_asm
1011

1112
r[asm.stable-targets]
@@ -58,14 +59,15 @@ option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nost
5859
options := "options(" option *("," option) [","] ")"
5960
operand := reg_operand / clobber_abi / options
6061
asm := "asm!(" format_string *("," format_string) *("," operand) [","] ")"
62+
naked_asm := "asm!(" format_string *("," format_string) *("," operand) [","] ")"
6163
global_asm := "global_asm!(" format_string *("," format_string) *("," operand) [","] ")"
6264
```
6365

6466
r[asm.scope]
6567
## Scope
6668

6769
r[asm.scope.intro]
68-
Inline assembly can be used in one of two ways.
70+
Inline assembly can be used in one of three ways.
6971

7072
r[asm.scope.asm]
7173
With the `asm!` macro, the assembly code is emitted in a function scope and integrated into the compiler-generated assembly code of a function.
@@ -78,6 +80,10 @@ unsafe { core::arch::asm!("/* {} */", in(reg) 0); }
7880
# }
7981
```
8082

83+
r[asm.scope.naked_asm]
84+
With the `naked_asm!` macro, the assembly code is emitted in a function scope and constitutes the full assembly code of a function.
85+
The `naked_asm!` macro is only allowed in [naked functions](../attributes/codegen.md#the-naked-attribute).
86+
8187
r[asm.scope.global_asm]
8288
With the `global_asm!` macro, the assembly code is emitted in a global scope, outside a function.
8389
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.
@@ -368,8 +374,11 @@ assert_eq!(y, 1);
368374
# }
369375
```
370376

377+
r[asm.operand-type.naked_asm-restriction]
378+
Because `naked_asm!` defines a whole function body, it can only use `sym` and `const` operands.
379+
371380
r[asm.operand-type.global_asm-restriction]
372-
Since `global_asm!` exists outside a function, it can only use `sym` and `const` operands.
381+
Because `global_asm!` exists outside a function, it can only use `sym` and `const` operands.
373382

374383
```rust,compile_fail
375384
# fn main() {}
@@ -1176,9 +1185,13 @@ unsafe { core::arch::asm!("mov {:e}, 1", out(reg) z, options(noreturn)); }
11761185
# #[cfg(not(target_arch = "x86_64"))] core::compile_error!("Test not supported on this arch");
11771186
```
11781187

1188+
r[asm.options.naked_asm-restriction]
1189+
`global_asm!` only supports the `att_syntax` and `raw` options.
1190+
The remaining options are not meaningful because the inline assembly defines the whole function body.
1191+
11791192
r[asm.options.global_asm-restriction]
11801193
`global_asm!` only supports the `att_syntax` and `raw` options.
1181-
The remaining options are not meaningful for global-scope inline assembly
1194+
The remaining options are not meaningful for global-scope inline assembly.
11821195

11831196
```rust,compile_fail
11841197
# fn main() {}
@@ -1331,6 +1344,43 @@ r[asm.rules.x86-prefix-restriction]
13311344
r[asm.rules.preserves_flags]
13321345
> **Note**: As a general rule, the flags covered by `preserves_flags` are those which are *not* preserved when performing a function call.
13331346
1347+
r[asm.naked-rules]
1348+
## Rules for naked inline assembly
1349+
1350+
r[asm.naked-rules.intro]
1351+
To avoid undefined behavior, these rules must be followed when using function-scope inline assembly in naked functions (`naked_asm!`):
1352+
1353+
r[asm.naked-rules.reg-not-input]
1354+
- 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.
1355+
- 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.
1356+
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).
1357+
1358+
r[asm.naked-rules.reg-not-output]
1359+
- Any callee-saved registers must have the same value upon exiting the asm block as they had on entry, otherwise behavior is undefined.
1360+
- Caller-saved registes may be used freely, even if they are not used for the return value.
1361+
1362+
r[asm.naked-rules.unwind]
1363+
- Behavior is undefined if execution unwinds out of an asm block.
1364+
- This also applies if the assembly code calls a function which then unwinds.
1365+
1366+
r[asm.naked-rules.noreturn]
1367+
- Behavior is undefined if execution falls through to the end of the asm block.
1368+
1369+
r[asm.naked-rules.mem-same-as-ffi]
1370+
- The set of memory locations that assembly code is allowed to read and write are the same as those allowed for an FFI function.
1371+
- Refer to the unsafe code guidelines for the exact rules.
1372+
- These rules do not apply to memory which is private to the asm code, such as stack space allocated within the asm block.
1373+
1374+
r[asm.naked-rules.black-box]
1375+
- The compiler cannot assume that the instructions in the asm are the ones that will actually end up executed.
1376+
- 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.
1377+
- Runtime code patching is allowed, via target-specific mechanisms.
1378+
- 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.
1379+
1380+
r[asm.naked-rules.not-exactly-once]
1381+
- You cannot assume that an `naked_asm!` block will appear exactly once in the output binary.
1382+
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.
1383+
13341384
r[asm.validity]
13351385
### Correctness and Validity
13361386

0 commit comments

Comments
 (0)