Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

naked functions #1689

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ The following is an index of all built-in attributes.
- Code generation
- [`inline`] --- Hint to inline code.
- [`cold`] --- Hint that a function is unlikely to be called.
- [`naked`] - Prevent the compiler from emitting a function prologue.
- [`no_builtins`] --- Disables use of certain built-in functions.
- [`target_feature`] --- Configure platform-specific code generation.
- [`track_caller`] --- Pass the parent call location to `std::panic::Location::caller()`.
Expand Down Expand Up @@ -367,6 +368,7 @@ The following is an index of all built-in attributes.
[`macro_export`]: macros-by-example.md#path-based-scope
[`macro_use`]: macros-by-example.md#the-macro_use-attribute
[`must_use`]: attributes/diagnostics.md#the-must_use-attribute
[`naked`]: attributes/codegen.md#the-naked-attribute
[`no_builtins`]: attributes/codegen.md#the-no_builtins-attribute
[`no_implicit_prelude`]: names/preludes.md#the-no_implicit_prelude-attribute
[`no_link`]: items/extern-crates.md#the-no_link-attribute
Expand Down
50 changes: 49 additions & 1 deletion src/attributes/codegen.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,46 @@ r[attributes.codegen.cold]
The *`cold` [attribute]* suggests that the attributed function is unlikely to
be called.

## The `naked` attribute

r[attributes.codegen.naked]

r[attributes.codegen.naked.intro]
The *`naked` [attribute]* prevents the compiler from emitting a function prologue and
epilogue for the attributed function.

r[attributes.codegen.naked.body]
The [function body] must consist of exactly one [`naked_asm!`] macro invocation, which
may be enclosed within an [unsafe block].

r[attributes.codegen.naked.prologue-epilogue]
No function prologue or epilogue are generated for the attributed function: the contents
of the `naked_asm!` invocation make up the full body of a naked function.

r[attributes.codegen.naked.call-stack]
The asm code will have a valid call stack and register state on entry as per the signature and calling convention of the function.

r[attributes.codegen.naked.no-duplication]
The asm code may not be duplicated by the compiler.
This property is important for naked functions that define symbols in the assembly code.
Comment on lines +73 to +75
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so, something I just thought of: we do duplicate the assembly when monomorphizing generic naked functions. So this phrasing should be a bit more specific I think.


r[attributes.codegen.naked.unsafe-function]
A naked function that makes use of registers in a way that does not conform
to the specified calling convention imposes additional safety invariants on its caller,
and therefore must be marked as an [unsafe function].

r[attributes.codegen.naked.unused-variables]
The [`unused_variables`] lint is suppressed within naked functions.

r[attributes.codegen.naked.inline]
A naked function cannot be attributed by the [`inline`](#the-inline-attribute) attribute.

r[attributes.codegen.naked.track_caller]
A naked function cannot be attributed by the [`track_caller`](#the-track_caller-attribute) attribute.

r[attributes.codegen.naked.testing]
A naked function cannot be attributed by [the testing attributes](testing.md).

## The `no_builtins` attribute

r[attributes.codegen.no_builtins]
Expand Down Expand Up @@ -469,14 +509,22 @@ trait object whose methods are attributed.
[`-C target-feature`]: ../../rustc/codegen-options/index.html#target-feature
[`is_x86_feature_detected`]: ../../std/arch/macro.is_x86_feature_detected.html
[`is_aarch64_feature_detected`]: ../../std/arch/macro.is_aarch64_feature_detected.html
[`naked_asm!`]: ../inline-assembly.md
[`inline`]: #the-inline-attribute
[`track_caller`]: #the-track-caller-attribute
[`target_feature` conditional compilation option]: ../conditional-compilation.md#target_feature
[`unused_variables`]: ../../rustc/lints/listing/warn-by-default.html#unused-variables
[attribute]: ../attributes.md
[attributes]: ../attributes.md
[FFI-safe]: ../../rustc/lints/listing/warn-by-default.html#improper-ctypes-definitions
[function body]: ../items/functions.md#function-body
[functions]: ../items/functions.md
[rules for inline assembly]: ../inline-assembly.md#rules-for-inline-assembly
[target architecture]: ../conditional-compilation.md#target_arch
[trait]: ../items/traits.md
[undefined behavior]: ../behavior-considered-undefined.md
[unsafe function]: ../unsafe-keyword.md
[unsafe block]: ../unsafe-blocks.md
[unsafe function]: ../unsafe-functions.md
[rust-abi]: ../items/external-blocks.md#abi
[`Location`]: core::panic::Location

Expand Down
55 changes: 51 additions & 4 deletions src/inline-assembly.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
r[asm]

r[asm.intro]
Support for inline assembly is provided via the [`asm!`] and [`global_asm!`] macros.
Support for inline assembly is provided via the [`asm!`], [`naked_asm!`] and [`global_asm!`] macros.
It can be used to embed handwritten assembly in the assembly output generated by the compiler.

[`asm!`]: core::arch::asm
[`naked_asm!`]: core::arch::naked_asm
[`global_asm!`]: core::arch::global_asm

r[asm.stable-targets]
Expand Down Expand Up @@ -61,6 +62,7 @@ option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nost
options := "options(" option *("," option) [","] ")"
operand := reg_operand / clobber_abi / options
asm := "asm!(" format_string *("," format_string) *("," operand) [","] ")"
naked_asm := "asm!(" format_string *("," format_string) *("," operand) [","] ")"
global_asm := "global_asm!(" format_string *("," format_string) *("," operand) [","] ")"
```

Expand All @@ -69,13 +71,17 @@ global_asm := "global_asm!(" format_string *("," format_string) *("," operand) [
r[asm.scope]

r[asm.scope.intro]
Inline assembly can be used in one of two ways.
Inline assembly can be used in one of three ways.

r[asm.scope.asm]
With the `asm!` macro, the assembly code is emitted in a function scope and integrated into the compiler-generated assembly code of a function.
This assembly code must obey [strict rules](#rules-for-inline-assembly) to avoid undefined behavior.
Note that in some cases the compiler may choose to emit the assembly code as a separate function and generate a call to it.

r[asm.scope.naked_asm]
With the `naked_asm!` macro, the assembly code is emitted in a function scope and constitutes the full assembly code of a function.
The `naked_asm!` macro is only allowed in [naked functions](attributes/codegen.md#the-naked-attribute).

r[asm.scope.global_asm]
With the `global_asm!` macro, the assembly code is emitted in a global scope, outside a function.
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.
Expand Down Expand Up @@ -185,8 +191,11 @@ Operand expressions are evaluated from left to right, just like function call ar
After the `asm!` has executed, outputs are written to in left to right order.
This is significant if two outputs point to the same place: that place will contain the value of the rightmost output.

r[asm.operand-type.naked_asm-restriction]
Because `naked_asm!` defines a whole function body, it can only use `sym` and `const` operands.

r[asm.operand-type.global_asm-restriction]
Since `global_asm!` exists outside a function, it can only use `sym` and `const` operands.
Because `global_asm!` exists outside a function, it can only use `sym` and `const` operands.

## Register operands

Expand Down Expand Up @@ -578,9 +587,13 @@ r[asm.options.checks.pure]
r[asm.options.checks.noreturn]
- It is a compile-time error to specify `noreturn` on an asm block with outputs.

r[asm.options.naked_asm-restriction]
`naked_asm!` only supports the `att_syntax` and `raw` options.
The remaining options are not meaningful because the inline assembly defines the whole function body.

r[asm.options.global_asm-restriction]
`global_asm!` only supports the `att_syntax` and `raw` options.
The remaining options are not meaningful for global-scope inline assembly
The remaining options are not meaningful for global-scope inline assembly.

## Rules for inline assembly

Expand Down Expand Up @@ -693,6 +706,40 @@ r[asm.rules.x86-prefix-restriction]
r[asm.rules.preserves_flags]
> **Note**: As a general rule, the flags covered by `preserves_flags` are those which are *not* preserved when performing a function call.

## Rules for naked inline assembly

r[asm.naked-rules]

r[asm.naked-rules.intro]
To avoid undefined behavior, these rules must be followed when using function-scope inline assembly in naked functions (`naked_asm!`):

r[asm.naked-rules.reg-not-input]
- 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.
- 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).

r[asm.naked-rules.reg-not-output]
- Any callee-saved registers must have the same value upon return as they had on entry, otherwise behavior is undefined.
- Caller-saved registes may be used freely, even if they are not used for the return value.

r[asm.naked-rules.unwind]
- Behavior is undefined if execution unwinds out of an asm block.
- This also applies if the assembly code calls a function which then unwinds.

r[asm.naked-rules.noreturn]
- Behavior is undefined if execution falls through to the end of the asm block.
folkertdev marked this conversation as resolved.
Show resolved Hide resolved
- the assembly code is expected to contain a return instruction or to diverge

r[asm.naked-rules.mem-same-as-ffi]
- The set of memory locations that assembly code is allowed to read and write are the same as those allowed for an FFI function.
- Refer to the unsafe code guidelines for the exact rules.
- These rules do not apply to memory which is private to the asm code, such as stack space allocated within the asm block.

r[asm.naked-rules.black-box]
- The compiler cannot assume that the instructions in the asm are the ones that will actually end up executed.
- 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.
- Runtime code patching is allowed, via target-specific mechanisms.

### Correctness and Validity

r[asm.validity]
Expand Down