diff --git a/src/attributes.md b/src/attributes.md index af3285edc..6cc94b85c 100644 --- a/src/attributes.md +++ b/src/attributes.md @@ -287,6 +287,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()`. @@ -363,6 +364,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 diff --git a/src/attributes/codegen.md b/src/attributes/codegen.md index ab9295c3b..64ce6f05c 100644 --- a/src/attributes/codegen.md +++ b/src/attributes/codegen.md @@ -49,10 +49,50 @@ r[attributes.codegen.cold] The *`cold` [attribute]* suggests that the attributed function is unlikely to be called. +r[attributes.codegen.naked] +## 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, except when monomorphizing polymorphic functions. +This property is important for naked functions that define symbols in the assembly code. + +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). + r[attributes.codegen.no_builtins] ## The `no_builtins` attribute - The *`no_builtins` [attribute]* may be applied at the crate level to disable optimizing certain code patterns to invocations of library functions that are assumed to exist. @@ -463,14 +503,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 diff --git a/src/inline-assembly.md b/src/inline-assembly.md index 39a129393..23829e782 100644 --- a/src/inline-assembly.md +++ b/src/inline-assembly.md @@ -2,10 +2,11 @@ r[asm] # Inline assembly 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] @@ -58,6 +59,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 := "naked_asm!(" format_string *("," format_string) *("," operand) [","] ")" global_asm := "global_asm!(" format_string *("," format_string) *("," operand) [","] ")" ``` @@ -65,7 +67,7 @@ r[asm.scope] ## 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. @@ -78,6 +80,10 @@ unsafe { core::arch::asm!("/* {} */", in(reg) 0); } # } ``` +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. @@ -368,8 +374,11 @@ assert_eq!(y, 1); # } ``` +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. ```rust,compile_fail # fn main() {} @@ -1176,9 +1185,13 @@ unsafe { core::arch::asm!("mov {:e}, 1", out(reg) z, options(noreturn)); } # #[cfg(not(target_arch = "x86_64"))] core::compile_error!("Test not supported on this arch"); ``` +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. ```rust,compile_fail # fn main() {} @@ -1331,6 +1344,39 @@ 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. +r[asm.naked-rules] +## Rules for naked inline assembly + +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. + - 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. + r[asm.validity] ### Correctness and Validity