Skip to content

Commit e42068d

Browse files
committedApr 19, 2025
document naked_asm!
1 parent 69d5534 commit e42068d

File tree

2 files changed

+56
-6
lines changed

2 files changed

+56
-6
lines changed
 

‎src/attributes/codegen.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ No function prologue or epilogue are generated for the attributed function: the
6464
of the `naked_asm!` invocation make up the full body of a naked function.
6565

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

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

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

‎src/inline-assembly.md

+54-4
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.
@@ -384,8 +390,11 @@ assert_eq!(y, 1);
384390
# }
385391
```
386392

393+
r[asm.operand-type.naked_asm-restriction]
394+
Because `naked_asm!` defines a whole function body, it can only use `sym` and `const` operands.
395+
387396
r[asm.operand-type.global_asm-restriction]
388-
Since `global_asm!` exists outside a function, it can only use `sym` and `const` operands.
397+
Because `global_asm!` exists outside a function, it can only use `sym` and `const` operands.
389398

390399
```rust,compile_fail
391400
# fn main() {}
@@ -1206,9 +1215,13 @@ unsafe { core::arch::asm!("mov {:e}, 1", out(reg) z, options(noreturn)); }
12061215
# #[cfg(not(target_arch = "x86_64"))] core::compile_error!("Test not supported on this arch");
12071216
```
12081217

1218+
r[asm.options.naked_asm-restriction]
1219+
`global_asm!` only supports the `att_syntax` and `raw` options.
1220+
The remaining options are not meaningful because the inline assembly defines the whole function body.
1221+
12091222
r[asm.options.global_asm-restriction]
12101223
`global_asm!` only supports the `att_syntax` and `raw` options.
1211-
The remaining options are not meaningful for global-scope inline assembly
1224+
The remaining options are not meaningful for global-scope inline assembly.
12121225

12131226
```rust,compile_fail
12141227
# fn main() {}
@@ -1362,6 +1375,43 @@ r[asm.rules.preserves_flags]
13621375
> [!NOTE]
13631376
> As a general rule, the flags covered by `preserves_flags` are those which are *not* preserved when performing a function call.
13641377
1378+
r[asm.naked-rules]
1379+
## Rules for naked inline assembly
1380+
1381+
r[asm.naked-rules.intro]
1382+
To avoid undefined behavior, these rules must be followed when using function-scope inline assembly in naked functions (`naked_asm!`):
1383+
1384+
r[asm.naked-rules.reg-not-input]
1385+
- 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.
1386+
- 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.
1387+
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).
1388+
1389+
r[asm.naked-rules.reg-not-output]
1390+
- Any callee-saved registers must have the same value upon exiting the asm block as they had on entry, otherwise behavior is undefined.
1391+
- Caller-saved registes may be used freely, even if they are not used for the return value.
1392+
1393+
r[asm.naked-rules.unwind]
1394+
- Behavior is undefined if execution unwinds out of an asm block.
1395+
- This also applies if the assembly code calls a function which then unwinds.
1396+
1397+
r[asm.naked-rules.noreturn]
1398+
- Behavior is undefined if execution falls through to the end of the asm block.
1399+
1400+
r[asm.naked-rules.mem-same-as-ffi]
1401+
- The set of memory locations that assembly code is allowed to read and write are the same as those allowed for an FFI function.
1402+
- Refer to the unsafe code guidelines for the exact rules.
1403+
- These rules do not apply to memory which is private to the asm code, such as stack space allocated within the asm block.
1404+
1405+
r[asm.naked-rules.black-box]
1406+
- The compiler cannot assume that the instructions in the asm are the ones that will actually end up executed.
1407+
- 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.
1408+
- Runtime code patching is allowed, via target-specific mechanisms.
1409+
- 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.
1410+
1411+
r[asm.naked-rules.not-exactly-once]
1412+
- You cannot assume that an `naked_asm!` block will appear exactly once in the output binary.
1413+
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.
1414+
13651415
r[asm.validity]
13661416
### Correctness and Validity
13671417

0 commit comments

Comments
 (0)