-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Tracking Issue for RFC #2972: Constrained Naked Functions #90957
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
Comments
"produce a clear warning if any of the above suggestions are not heeded" in RFC seems to contain typo |
This is implemented, checking the box. Adding a new step: "Confirm that all errors and warnings are emitted properly". |
Request for StabilizationA proposal that the SummaryAdds a new attribute, The body of a naked function must consist of a single An example of a naked function: const THREE: usize = 3;
#[naked]
/// Adds three to a number and returns the result.
pub extern "sysv64" fn add_n(number: usize) -> usize {
// SAFETY: the validity of these registers is guaranteed according to the "sysv64" ABI
unsafe {
std::arch::asm!(
"add rdi, {}",
"mov rax, rdi",
"ret",
const THREE,
options(noreturn)
);
}
} DocumentationThe Rust Reference: rust-lang/reference#1153 Tests
HistoryThis feature was originally proposed in RFC 1201, filed on 2015-07-10 and accepted on 2016-03-21. Support for this feature was added in #32410, landing on 2016-03-23. Development languished for several years as it was realized that the semantics given in RFC 1201 were insufficiently specific. To address this, a minimal subset of naked functions was specified by RFC 2972, filed on 2020-08-07 and accepted on 2021-11-16. Prior to the acceptance of RFC 2972, all of the stricter behavior specified by RFC 2972 was implemented as a series of warn-by-default lints that would trigger on existing uses of the Unresolved Questions
|
This stabilizes the feature described in RFC 2972, which supersedes the earlier RFC 1201. Closes rust-lang#32408 Closes rust-lang#90957
There is no observable difference between LLVM adding an epilogue and a following unnamed function starting with instructions identical to a regular epilogue. |
@bjorn3 I believe it can cause problems in circumstances such as #32408 (comment) . If someone were to work around that issue by assuming the existence of extra instructions and manually accounting for it, then their code would be broken if Rust ever stopped generating those instructions. It is this sort of edge case that this defensive wording is designed to address. |
I believe it's possible to observe a difference when |
👍 for stabilizing, though I'd like to make sure that there's consensus on #32408 (comment) . |
Shall we stabilize constrained naked functions? @rfcbot merge |
Team member @joshtriplett has proposed to merge this. The next step is review by the rest of the tagged team members: No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
I'd like to have a whitelist of attributes that are allowed to be applies to a naked function. In the future we may want to lower naked functions directly to LLVM module-level assembly instead of using LLVM's native naked function support. For that to happen rustc needs to be able to manually translate any attributes (e.g. |
Why, because of the epilogue issue? Personally I would much rather see that fixed on LLVM’s end, rather than going to great lengths to work around it in rustc. Or is there another reason? |
Lowering to |
@comex In addition to the epilogue issue, it seems the inlining issue could also be resolved by lowering to @Amanieu I'd be interested in seeing such a list. Obviously part of the appeal of naked functions is that they can be treated just like a normal function in most cases, which includes the ability to be marked with attributes (e.g. |
Most attributes that work with arbitrary functions should work with naked functions IMO. Taking the list here, those make sense to use with naked fns:
The only ones that I think make sense to disallow are those in the "Code Generation" category:
|
yes, fair point. I was going to make some argument about most
My idea was that it is at least a signal to the programmer to check that their assembly satisfies the constraints: if they deem the lint fired incorrectly, they can just But I agree that it is hard/impossible to actually make it robust (enough) to work in practice. |
That's not entirely true: ELF symbols have a length and typically any padding bytes are not included in this length since they are inserted by the linker. If we append ud2 then this will observably be different when inspecting the symbol table. |
Given that rustc generates inline assembly which defines the symbol, in the inline assembly rustc can specify the length of the symbol to exclude the ud2 instruction. |
Please don't insert UD2's and things like that (or similar things for non-x86 targets) in naked functions. One of the problems with the earlier iterations of naked functions, mentioned above, was that they did this, which made it impossible to have precise control over layout and size. Here's a motivating example: for example, consider two naked functions placed into a specific linker segment; both need to occupy exactly 4KiB (so, page sized on x86) and further they are both supposed to be aligned on 4K boundaries. One may not care what order they're put into the resulting binary, A before B or B before A, but the size and alignment requirements are absolute. They're not copied; instead, one relies on the linker to place them correctly. Adding extra UD2's at the end of these the NF's throws this off. I appreciate the arguments for safety here, and in Rust generally, but naked functions are already incredibly niche: if one is reaching for them one's doing something so far out of the ordinary for most programmers that trying to add a ud2 to catch bugs here feels superfluous. A response to this may be to use module-level assembly instead of naked functions for this sort of thing. While that's valid, there are some properties of naked functions that make them attractive versus global asm: symbol naming and visibility and so on. |
So in the cases when it's already aligned, there's no extra nop to replace, so no ud2 is emitted. So we're back in the territory of "ud2 sometimes, but not other times, and only in debug mode, and changing the preceding body can affect if a ud2 is there, or not". So in such a case, it is functionally impossible to rely on it and therefore going to masquerade a ton of bugs and cause strange behavior in some cases and not others. Some developers will rely on it being there, erroneously of course. But then be surprised when it's not there. Instead of strictly specifying the safety constraints that must hold, which are there already. Also, nops are there to indicate padding. ud2/similar are not padding instructions. It has side effects, and we cannot know how different environments/tools/chips are going to react to them being there, even if they're not hit (e.g. in the case of pipelining). There is a flimsy at best reason for emitting them, and a multitude of strong reasons not to emit them. Adding in such instructions is subverting expectation for some illusion of safety in a place that is very much opt-in and explicitly, objectively unsafe. |
codegen `#[naked]` functions using global asm tracking issue: rust-lang/rust#90957 Fixes #124375 This implements the approach suggested in the tracking issue: use the existing global assembly infrastructure to emit the body of `#[naked]` functions. The main advantage is that we now have full control over what gets generated, and are no longer dependent on LLVM not sneakily messing with our output (inlining, adding extra instructions, etc). I discussed this approach with `@Amanieu` and while I think the general direction is correct, there is probably a bunch of stuff that needs to change or move around here. I'll leave some inline comments on things that I'm not sure about. Combined with rust-lang/rust#127853, if both accepted, I think that resolves all steps from the tracking issue. r? `@Amanieu`
codegen `#[naked]` functions using global asm tracking issue: rust-lang/rust#90957 Fixes #124375 This implements the approach suggested in the tracking issue: use the existing global assembly infrastructure to emit the body of `#[naked]` functions. The main advantage is that we now have full control over what gets generated, and are no longer dependent on LLVM not sneakily messing with our output (inlining, adding extra instructions, etc). I discussed this approach with `@Amanieu` and while I think the general direction is correct, there is probably a bunch of stuff that needs to change or move around here. I'll leave some inline comments on things that I'm not sure about. Combined with rust-lang/rust#127853, if both accepted, I think that resolves all steps from the tracking issue. r? `@Amanieu`
Sorry for the double post, but just ran into a case where having a naked closure-like non-closure function would be extremely helpful. static IDT: [fn(); 1] = [
#[naked] // sadly not allowed
|| {}
]; Unless I'm missing something, this is the equivalent of #[naked]
fn some_fn(){}
static IDT: [fn(); 1] = [
some_fn
]; but is unfortunately not allowed. It would help to tidy up both the code and scope / symbol list when assembling certain types of embedded interrupt handler lists in macros. |
While still worse than a closure, it should at least tidy up the scope, what about defining the function in the static definition playground CodeNot sure how long the playground link will stay valid, copy-pasting the code here to prevent dead link problems.#![feature(naked_functions)]
use std::arch::naked_asm;
#[used]
static IDT: [extern "C" fn(); 2] = [
{
#[naked]
extern "C" fn some_fn(){
unsafe { naked_asm!("ret") }
}
some_fn
},
{
#[naked]
extern "C" fn some_fn(){
unsafe { naked_asm!("ret") }
}
some_fn
},
]; |
I think what you're missing is that naked functions cannot use the rust calling convention: they must always be an Therefore, even if the attribute worked in this position |
Ah yep, I figured I was missing something obvious. Thank you @Skgland and @folkertdev, the workaround works just fine :) Appreciate the info! |
…, r=ChrisDenton naked functions: on windows emit `.endef` without the symbol name tracking issue: rust-lang#90957 fixes rust-lang#138320 The `.endef` directive does not take the name as an argument. Apparently the LLVM x86_64 parser does accept this, but on i686 it's rejected. In general `i686` does some special name mangling stuff, so it's good to include it in the naked function tests. r? `@ChrisDenton` (because windows)
…, r=ChrisDenton naked functions: on windows emit `.endef` without the symbol name tracking issue: rust-lang#90957 fixes rust-lang#138320 The `.endef` directive does not take the name as an argument. Apparently the LLVM x86_64 parser does accept this, but on i686 it's rejected. In general `i686` does some special name mangling stuff, so it's good to include it in the naked function tests. r? ``@ChrisDenton`` (because windows)
…, r=ChrisDenton naked functions: on windows emit `.endef` without the symbol name tracking issue: rust-lang#90957 fixes rust-lang#138320 The `.endef` directive does not take the name as an argument. Apparently the LLVM x86_64 parser does accept this, but on i686 it's rejected. In general `i686` does some special name mangling stuff, so it's good to include it in the naked function tests. r? ```@ChrisDenton``` (because windows)
…, r=ChrisDenton naked functions: on windows emit `.endef` without the symbol name tracking issue: rust-lang#90957 fixes rust-lang#138320 The `.endef` directive does not take the name as an argument. Apparently the LLVM x86_64 parser does accept this, but on i686 it's rejected. In general `i686` does some special name mangling stuff, so it's good to include it in the naked function tests. r? ````@ChrisDenton```` (because windows)
Rollup merge of rust-lang#138346 - folkertdev:naked-asm-windows-endef, r=ChrisDenton naked functions: on windows emit `.endef` without the symbol name tracking issue: rust-lang#90957 fixes rust-lang#138320 The `.endef` directive does not take the name as an argument. Apparently the LLVM x86_64 parser does accept this, but on i686 it's rejected. In general `i686` does some special name mangling stuff, so it's good to include it in the naked function tests. r? ````@ChrisDenton```` (because windows)
…eature-gate, r=Amanieu add `naked_functions_target_feature` unstable feature tracking issue: rust-lang#138568 tagging rust-lang#134213 rust-lang#90957 This PR puts `#[target_feature(/* ... */)]` on `#[naked]` functions behind its own feature gate, so that naked functions can be stabilized. It turns out that supporting `target_feature` on naked functions is tricky on some targets, so we're splitting it out to not block stabilization of naked functions themselves. See the tracking issue for more information and workarounds. Note that at the time of writing, the `target_features` attribute is ignored when generating code for naked functions. r? `@Amanieu`
…eature-gate, r=Amanieu add `naked_functions_target_feature` unstable feature tracking issue: rust-lang#138568 tagging rust-lang#134213 rust-lang#90957 This PR puts `#[target_feature(/* ... */)]` on `#[naked]` functions behind its own feature gate, so that naked functions can be stabilized. It turns out that supporting `target_feature` on naked functions is tricky on some targets, so we're splitting it out to not block stabilization of naked functions themselves. See the tracking issue for more information and workarounds. Note that at the time of writing, the `target_features` attribute is ignored when generating code for naked functions. r? ``@Amanieu``
Rollup merge of rust-lang#138570 - folkertdev:naked-function-target-feature-gate, r=Amanieu add `naked_functions_target_feature` unstable feature tracking issue: rust-lang#138568 tagging rust-lang#134213 rust-lang#90957 This PR puts `#[target_feature(/* ... */)]` on `#[naked]` functions behind its own feature gate, so that naked functions can be stabilized. It turns out that supporting `target_feature` on naked functions is tricky on some targets, so we're splitting it out to not block stabilization of naked functions themselves. See the tracking issue for more information and workarounds. Note that at the time of writing, the `target_features` attribute is ignored when generating code for naked functions. r? ``@Amanieu``
…ns, r=tgross35,Amanieu,traviscross Stabilize `naked_functions` tracking issue: rust-lang#90957 request for stabilization on tracking issue: rust-lang#90957 (comment) reference PR: rust-lang/reference#1689 # Request for Stabilization Two years later, we're ready to try this again. Even though this issue is already marked as having passed FCP, given the amount of time that has passed and the changes in implementation strategy, we should follow the process again. ## Summary The `naked_functions` feature has two main parts: the `#[naked]` function attribute, and the `naked_asm!` macro. An example of a naked function: ```rust const THREE: usize = 3; #[naked] pub extern "sysv64" fn add_n(number: usize) -> usize { // SAFETY: the validity of the used registers // is guaranteed according to the "sysv64" ABI unsafe { core::arch::naked_asm!( "add rdi, {}", "mov rax, rdi", "ret", const THREE, ) } } ``` When the `#[naked]` attribute is applied to a function, the compiler won't emit a [function prologue](https://en.wikipedia.org/wiki/Function_prologue_and_epilogue) or epilogue when generating code for this function. This attribute is analogous to [`__attribute__((naked))`](https://developer.arm.com/documentation/100067/0608/Compiler-specific-Function--Variable--and-Type-Attributes/--attribute----naked---function-attribute) in C. The use of this feature allows the programmer to have precise control over the assembly that is generated for a given function. The body of a naked function must consist of a single `naked_asm!` invocation, a heavily restricted variant of the `asm!` macro: the only legal operands are `const` and `sym`, and the only legal options are `raw` and `att_syntax`. In lieu of specifying operands, the `naked_asm!` within a naked function relies on the function's calling convention to determine the validity of registers. ## Documentation The Rust Reference: rust-lang/reference#1689 (Previous PR: rust-lang/reference#1153) ## Tests * [tests/run-make/naked-symbol-visiblity](https://github.com./rust-lang/rust/tree/master/tests/codegen/naked-fn) verifies that `pub`, `#[no_mangle]` and `#[linkage = "..."]` work correctly for naked functions * [tests/codegen/naked-fn](https://github.com./rust-lang/rust/tree/master/tests/codegen/naked-fn) has tests for function alignment, use of generics, and validates the exact assembly output on linux, macos, windows and thumb * [tests/ui/asm/naked-*](https://github.com./rust-lang/rust/tree/master/tests/ui/asm) tests for incompatible attributes, generating errors around incorrect use of `naked_asm!`, etc ## Interaction with other (unstable) features ### [fn_align](rust-lang#82232) Combining `#[naked]` with `#[repr(align(N))]` works well, and is tested e.g. here - https://github.com./rust-lang/rust/blob/master/tests/codegen/naked-fn/aligned.rs - https://github.com./rust-lang/rust/blob/master/tests/codegen/naked-fn/min-function-alignment.rs It's tested extensively because we do need to explicitly support the `repr(align)` attribute (and make sure we e.g. don't mistake powers of two for number of bytes). ## History This feature was originally proposed in [RFC 1201](rust-lang/rfcs#1201), filed on 2015-07-10 and accepted on 2016-03-21. Support for this feature was added in [rust-lang#32410](rust-lang#32410), landing on 2016-03-23. Development languished for several years as it was realized that the semantics given in RFC 1201 were insufficiently specific. To address this, a minimal subset of naked functions was specified by [RFC 2972](rust-lang/rfcs#2972), filed on 2020-08-07 and accepted on 2021-11-16. Prior to the acceptance of RFC 2972, all of the stricter behavior specified by RFC 2972 was implemented as a series of warn-by-default lints that would trigger on existing uses of the `naked` attribute; these lints became hard errors in [rust-lang#93153](rust-lang#93153) on 2022-01-22. As a result, today RFC 2972 has completely superseded RFC 1201 in describing the semantics of the `naked` attribute. More recently, the `naked_asm!` macro was added to replace the earlier use of a heavily restricted `asm!` invocation. The `naked_asm!` name is clearer in error messages, and provides a place for documenting the specific requirements of inline assembly in naked functions. The implementation strategy was changed to emitting a global assembly block. In effect, an extern function ```rust extern "C" fn foo() { core::arch::naked_asm!("ret") } ``` is emitted as something similar to ```rust core::arch::global_asm!( "foo:", "ret" ); extern "C" { fn foo(); } ``` The codegen approach was chosen over the llvm naked function attribute because: - the rust compiler can guarantee the behavior (no sneaky additional instructions, no inlining, etc.) - behavior is the same on all backends (llvm, cranelift, gcc, etc) Finally, there is now an allow list of compatible attributes on naked functions, so that e.g. `#[inline]` is rejected with an error. The `#[target_feature]` attribute on naked functions was later made separately unstable, because implementing it is complex and we did not want to block naked functions themselves on how target features work on them. See also rust-lang#138568. relevant PRs for these recent changes - rust-lang#127853 - rust-lang#128651 - rust-lang#128004 - rust-lang#138570 - ### Various historical notes #### `noreturn` [RFC 2972](https://github.com./rust-lang/rfcs/blob/master/text/2972-constrained-naked.md) mentions that naked functions > must have a body which contains only a single asm!() statement which: > iii. must contain the noreturn option. Instead of `asm!`, the current implementation mandates that the body contain a single `naked_asm!` statement. The `naked_asm!` macro is a heavily restricted version of the `asm!` macro, making it easier to talk about and document the rules of assembly in naked functions and give dedicated error messages. For `naked_asm!`, the behavior of the `asm!`'s `noreturn` option is implicit. The `noreturn` option means that it is UB for control flow to fall through the end of the assembly block. With `asm!`, this option is usually used for blocks that diverge (and thus have no return and can be typed as `!`). With `naked_asm!`, the intent is different: usually naked funtions do return, but they must do so from within the assembly block. The `noreturn` option was used so that the compiler would not itself also insert a `ret` instruction at the very end. #### padding / `ud2` A `naked_asm!` block that violates the safety assumption that control flow must not fall through the end of the assembly block is UB. Because no return instruction is emitted, whatever bytes follow the naked function will be executed, resulting in truly undefined behavior. There has been discussion whether rustc should emit an invalid instruction (e.g. `ud2` on x86) after the `naked_asm!` block to at least fail early in the case of an invalid `naked_asm!`. It was however decided that it is more useful to guarantee that `#[naked]` functions NEVER contain any instructions besides those in the `naked_asm!` block. # unresolved questions None r? `@Amanieu` I've validated the tests on x86_64 and aarch64
…ns, r=tgross35,Amanieu,traviscross Stabilize `naked_functions` tracking issue: rust-lang#90957 request for stabilization on tracking issue: rust-lang#90957 (comment) reference PR: rust-lang/reference#1689 # Request for Stabilization Two years later, we're ready to try this again. Even though this issue is already marked as having passed FCP, given the amount of time that has passed and the changes in implementation strategy, we should follow the process again. ## Summary The `naked_functions` feature has two main parts: the `#[naked]` function attribute, and the `naked_asm!` macro. An example of a naked function: ```rust const THREE: usize = 3; #[naked] pub extern "sysv64" fn add_n(number: usize) -> usize { // SAFETY: the validity of the used registers // is guaranteed according to the "sysv64" ABI unsafe { core::arch::naked_asm!( "add rdi, {}", "mov rax, rdi", "ret", const THREE, ) } } ``` When the `#[naked]` attribute is applied to a function, the compiler won't emit a [function prologue](https://en.wikipedia.org/wiki/Function_prologue_and_epilogue) or epilogue when generating code for this function. This attribute is analogous to [`__attribute__((naked))`](https://developer.arm.com/documentation/100067/0608/Compiler-specific-Function--Variable--and-Type-Attributes/--attribute----naked---function-attribute) in C. The use of this feature allows the programmer to have precise control over the assembly that is generated for a given function. The body of a naked function must consist of a single `naked_asm!` invocation, a heavily restricted variant of the `asm!` macro: the only legal operands are `const` and `sym`, and the only legal options are `raw` and `att_syntax`. In lieu of specifying operands, the `naked_asm!` within a naked function relies on the function's calling convention to determine the validity of registers. ## Documentation The Rust Reference: rust-lang/reference#1689 (Previous PR: rust-lang/reference#1153) ## Tests * [tests/run-make/naked-symbol-visiblity](https://github.com./rust-lang/rust/tree/master/tests/codegen/naked-fn) verifies that `pub`, `#[no_mangle]` and `#[linkage = "..."]` work correctly for naked functions * [tests/codegen/naked-fn](https://github.com./rust-lang/rust/tree/master/tests/codegen/naked-fn) has tests for function alignment, use of generics, and validates the exact assembly output on linux, macos, windows and thumb * [tests/ui/asm/naked-*](https://github.com./rust-lang/rust/tree/master/tests/ui/asm) tests for incompatible attributes, generating errors around incorrect use of `naked_asm!`, etc ## Interaction with other (unstable) features ### [fn_align](rust-lang#82232) Combining `#[naked]` with `#[repr(align(N))]` works well, and is tested e.g. here - https://github.com./rust-lang/rust/blob/master/tests/codegen/naked-fn/aligned.rs - https://github.com./rust-lang/rust/blob/master/tests/codegen/naked-fn/min-function-alignment.rs It's tested extensively because we do need to explicitly support the `repr(align)` attribute (and make sure we e.g. don't mistake powers of two for number of bytes). ## History This feature was originally proposed in [RFC 1201](rust-lang/rfcs#1201), filed on 2015-07-10 and accepted on 2016-03-21. Support for this feature was added in [rust-lang#32410](rust-lang#32410), landing on 2016-03-23. Development languished for several years as it was realized that the semantics given in RFC 1201 were insufficiently specific. To address this, a minimal subset of naked functions was specified by [RFC 2972](rust-lang/rfcs#2972), filed on 2020-08-07 and accepted on 2021-11-16. Prior to the acceptance of RFC 2972, all of the stricter behavior specified by RFC 2972 was implemented as a series of warn-by-default lints that would trigger on existing uses of the `naked` attribute; these lints became hard errors in [rust-lang#93153](rust-lang#93153) on 2022-01-22. As a result, today RFC 2972 has completely superseded RFC 1201 in describing the semantics of the `naked` attribute. More recently, the `naked_asm!` macro was added to replace the earlier use of a heavily restricted `asm!` invocation. The `naked_asm!` name is clearer in error messages, and provides a place for documenting the specific requirements of inline assembly in naked functions. The implementation strategy was changed to emitting a global assembly block. In effect, an extern function ```rust extern "C" fn foo() { core::arch::naked_asm!("ret") } ``` is emitted as something similar to ```rust core::arch::global_asm!( "foo:", "ret" ); extern "C" { fn foo(); } ``` The codegen approach was chosen over the llvm naked function attribute because: - the rust compiler can guarantee the behavior (no sneaky additional instructions, no inlining, etc.) - behavior is the same on all backends (llvm, cranelift, gcc, etc) Finally, there is now an allow list of compatible attributes on naked functions, so that e.g. `#[inline]` is rejected with an error. The `#[target_feature]` attribute on naked functions was later made separately unstable, because implementing it is complex and we did not want to block naked functions themselves on how target features work on them. See also rust-lang#138568. relevant PRs for these recent changes - rust-lang#127853 - rust-lang#128651 - rust-lang#128004 - rust-lang#138570 - ### Various historical notes #### `noreturn` [RFC 2972](https://github.com./rust-lang/rfcs/blob/master/text/2972-constrained-naked.md) mentions that naked functions > must have a body which contains only a single asm!() statement which: > iii. must contain the noreturn option. Instead of `asm!`, the current implementation mandates that the body contain a single `naked_asm!` statement. The `naked_asm!` macro is a heavily restricted version of the `asm!` macro, making it easier to talk about and document the rules of assembly in naked functions and give dedicated error messages. For `naked_asm!`, the behavior of the `asm!`'s `noreturn` option is implicit. The `noreturn` option means that it is UB for control flow to fall through the end of the assembly block. With `asm!`, this option is usually used for blocks that diverge (and thus have no return and can be typed as `!`). With `naked_asm!`, the intent is different: usually naked funtions do return, but they must do so from within the assembly block. The `noreturn` option was used so that the compiler would not itself also insert a `ret` instruction at the very end. #### padding / `ud2` A `naked_asm!` block that violates the safety assumption that control flow must not fall through the end of the assembly block is UB. Because no return instruction is emitted, whatever bytes follow the naked function will be executed, resulting in truly undefined behavior. There has been discussion whether rustc should emit an invalid instruction (e.g. `ud2` on x86) after the `naked_asm!` block to at least fail early in the case of an invalid `naked_asm!`. It was however decided that it is more useful to guarantee that `#[naked]` functions NEVER contain any instructions besides those in the `naked_asm!` block. # unresolved questions None r? ``@Amanieu`` I've validated the tests on x86_64 and aarch64
Rollup merge of rust-lang#134213 - folkertdev:stabilize-naked-functions, r=tgross35,Amanieu,traviscross Stabilize `naked_functions` tracking issue: rust-lang#90957 request for stabilization on tracking issue: rust-lang#90957 (comment) reference PR: rust-lang/reference#1689 # Request for Stabilization Two years later, we're ready to try this again. Even though this issue is already marked as having passed FCP, given the amount of time that has passed and the changes in implementation strategy, we should follow the process again. ## Summary The `naked_functions` feature has two main parts: the `#[naked]` function attribute, and the `naked_asm!` macro. An example of a naked function: ```rust const THREE: usize = 3; #[naked] pub extern "sysv64" fn add_n(number: usize) -> usize { // SAFETY: the validity of the used registers // is guaranteed according to the "sysv64" ABI unsafe { core::arch::naked_asm!( "add rdi, {}", "mov rax, rdi", "ret", const THREE, ) } } ``` When the `#[naked]` attribute is applied to a function, the compiler won't emit a [function prologue](https://en.wikipedia.org/wiki/Function_prologue_and_epilogue) or epilogue when generating code for this function. This attribute is analogous to [`__attribute__((naked))`](https://developer.arm.com/documentation/100067/0608/Compiler-specific-Function--Variable--and-Type-Attributes/--attribute----naked---function-attribute) in C. The use of this feature allows the programmer to have precise control over the assembly that is generated for a given function. The body of a naked function must consist of a single `naked_asm!` invocation, a heavily restricted variant of the `asm!` macro: the only legal operands are `const` and `sym`, and the only legal options are `raw` and `att_syntax`. In lieu of specifying operands, the `naked_asm!` within a naked function relies on the function's calling convention to determine the validity of registers. ## Documentation The Rust Reference: rust-lang/reference#1689 (Previous PR: rust-lang/reference#1153) ## Tests * [tests/run-make/naked-symbol-visiblity](https://github.com./rust-lang/rust/tree/master/tests/codegen/naked-fn) verifies that `pub`, `#[no_mangle]` and `#[linkage = "..."]` work correctly for naked functions * [tests/codegen/naked-fn](https://github.com./rust-lang/rust/tree/master/tests/codegen/naked-fn) has tests for function alignment, use of generics, and validates the exact assembly output on linux, macos, windows and thumb * [tests/ui/asm/naked-*](https://github.com./rust-lang/rust/tree/master/tests/ui/asm) tests for incompatible attributes, generating errors around incorrect use of `naked_asm!`, etc ## Interaction with other (unstable) features ### [fn_align](rust-lang#82232) Combining `#[naked]` with `#[repr(align(N))]` works well, and is tested e.g. here - https://github.com./rust-lang/rust/blob/master/tests/codegen/naked-fn/aligned.rs - https://github.com./rust-lang/rust/blob/master/tests/codegen/naked-fn/min-function-alignment.rs It's tested extensively because we do need to explicitly support the `repr(align)` attribute (and make sure we e.g. don't mistake powers of two for number of bytes). ## History This feature was originally proposed in [RFC 1201](rust-lang/rfcs#1201), filed on 2015-07-10 and accepted on 2016-03-21. Support for this feature was added in [rust-lang#32410](rust-lang#32410), landing on 2016-03-23. Development languished for several years as it was realized that the semantics given in RFC 1201 were insufficiently specific. To address this, a minimal subset of naked functions was specified by [RFC 2972](rust-lang/rfcs#2972), filed on 2020-08-07 and accepted on 2021-11-16. Prior to the acceptance of RFC 2972, all of the stricter behavior specified by RFC 2972 was implemented as a series of warn-by-default lints that would trigger on existing uses of the `naked` attribute; these lints became hard errors in [rust-lang#93153](rust-lang#93153) on 2022-01-22. As a result, today RFC 2972 has completely superseded RFC 1201 in describing the semantics of the `naked` attribute. More recently, the `naked_asm!` macro was added to replace the earlier use of a heavily restricted `asm!` invocation. The `naked_asm!` name is clearer in error messages, and provides a place for documenting the specific requirements of inline assembly in naked functions. The implementation strategy was changed to emitting a global assembly block. In effect, an extern function ```rust extern "C" fn foo() { core::arch::naked_asm!("ret") } ``` is emitted as something similar to ```rust core::arch::global_asm!( "foo:", "ret" ); extern "C" { fn foo(); } ``` The codegen approach was chosen over the llvm naked function attribute because: - the rust compiler can guarantee the behavior (no sneaky additional instructions, no inlining, etc.) - behavior is the same on all backends (llvm, cranelift, gcc, etc) Finally, there is now an allow list of compatible attributes on naked functions, so that e.g. `#[inline]` is rejected with an error. The `#[target_feature]` attribute on naked functions was later made separately unstable, because implementing it is complex and we did not want to block naked functions themselves on how target features work on them. See also rust-lang#138568. relevant PRs for these recent changes - rust-lang#127853 - rust-lang#128651 - rust-lang#128004 - rust-lang#138570 - ### Various historical notes #### `noreturn` [RFC 2972](https://github.com./rust-lang/rfcs/blob/master/text/2972-constrained-naked.md) mentions that naked functions > must have a body which contains only a single asm!() statement which: > iii. must contain the noreturn option. Instead of `asm!`, the current implementation mandates that the body contain a single `naked_asm!` statement. The `naked_asm!` macro is a heavily restricted version of the `asm!` macro, making it easier to talk about and document the rules of assembly in naked functions and give dedicated error messages. For `naked_asm!`, the behavior of the `asm!`'s `noreturn` option is implicit. The `noreturn` option means that it is UB for control flow to fall through the end of the assembly block. With `asm!`, this option is usually used for blocks that diverge (and thus have no return and can be typed as `!`). With `naked_asm!`, the intent is different: usually naked funtions do return, but they must do so from within the assembly block. The `noreturn` option was used so that the compiler would not itself also insert a `ret` instruction at the very end. #### padding / `ud2` A `naked_asm!` block that violates the safety assumption that control flow must not fall through the end of the assembly block is UB. Because no return instruction is emitted, whatever bytes follow the naked function will be executed, resulting in truly undefined behavior. There has been discussion whether rustc should emit an invalid instruction (e.g. `ud2` on x86) after the `naked_asm!` block to at least fail early in the case of an invalid `naked_asm!`. It was however decided that it is more useful to guarantee that `#[naked]` functions NEVER contain any instructions besides those in the `naked_asm!` block. # unresolved questions None r? ``@Amanieu`` I've validated the tests on x86_64 and aarch64
With the stabilization at #134213, I believe this can be closed. |
…oss35,Amanieu,traviscross Stabilize `naked_functions` tracking issue: rust-lang/rust#90957 request for stabilization on tracking issue: rust-lang/rust#90957 (comment) reference PR: rust-lang/reference#1689 # Request for Stabilization Two years later, we're ready to try this again. Even though this issue is already marked as having passed FCP, given the amount of time that has passed and the changes in implementation strategy, we should follow the process again. ## Summary The `naked_functions` feature has two main parts: the `#[naked]` function attribute, and the `naked_asm!` macro. An example of a naked function: ```rust const THREE: usize = 3; #[naked] pub extern "sysv64" fn add_n(number: usize) -> usize { // SAFETY: the validity of the used registers // is guaranteed according to the "sysv64" ABI unsafe { core::arch::naked_asm!( "add rdi, {}", "mov rax, rdi", "ret", const THREE, ) } } ``` When the `#[naked]` attribute is applied to a function, the compiler won't emit a [function prologue](https://en.wikipedia.org/wiki/Function_prologue_and_epilogue) or epilogue when generating code for this function. This attribute is analogous to [`__attribute__((naked))`](https://developer.arm.com/documentation/100067/0608/Compiler-specific-Function--Variable--and-Type-Attributes/--attribute----naked---function-attribute) in C. The use of this feature allows the programmer to have precise control over the assembly that is generated for a given function. The body of a naked function must consist of a single `naked_asm!` invocation, a heavily restricted variant of the `asm!` macro: the only legal operands are `const` and `sym`, and the only legal options are `raw` and `att_syntax`. In lieu of specifying operands, the `naked_asm!` within a naked function relies on the function's calling convention to determine the validity of registers. ## Documentation The Rust Reference: rust-lang/reference#1689 (Previous PR: rust-lang/reference#1153) ## Tests * [tests/run-make/naked-symbol-visiblity](https://github.com./rust-lang/rust/tree/master/tests/codegen/naked-fn) verifies that `pub`, `#[no_mangle]` and `#[linkage = "..."]` work correctly for naked functions * [tests/codegen/naked-fn](https://github.com./rust-lang/rust/tree/master/tests/codegen/naked-fn) has tests for function alignment, use of generics, and validates the exact assembly output on linux, macos, windows and thumb * [tests/ui/asm/naked-*](https://github.com./rust-lang/rust/tree/master/tests/ui/asm) tests for incompatible attributes, generating errors around incorrect use of `naked_asm!`, etc ## Interaction with other (unstable) features ### [fn_align](rust-lang/rust#82232) Combining `#[naked]` with `#[repr(align(N))]` works well, and is tested e.g. here - https://github.com./rust-lang/rust/blob/master/tests/codegen/naked-fn/aligned.rs - https://github.com./rust-lang/rust/blob/master/tests/codegen/naked-fn/min-function-alignment.rs It's tested extensively because we do need to explicitly support the `repr(align)` attribute (and make sure we e.g. don't mistake powers of two for number of bytes). ## History This feature was originally proposed in [RFC 1201](rust-lang/rfcs#1201), filed on 2015-07-10 and accepted on 2016-03-21. Support for this feature was added in [#32410](rust-lang/rust#32410), landing on 2016-03-23. Development languished for several years as it was realized that the semantics given in RFC 1201 were insufficiently specific. To address this, a minimal subset of naked functions was specified by [RFC 2972](rust-lang/rfcs#2972), filed on 2020-08-07 and accepted on 2021-11-16. Prior to the acceptance of RFC 2972, all of the stricter behavior specified by RFC 2972 was implemented as a series of warn-by-default lints that would trigger on existing uses of the `naked` attribute; these lints became hard errors in [#93153](rust-lang/rust#93153) on 2022-01-22. As a result, today RFC 2972 has completely superseded RFC 1201 in describing the semantics of the `naked` attribute. More recently, the `naked_asm!` macro was added to replace the earlier use of a heavily restricted `asm!` invocation. The `naked_asm!` name is clearer in error messages, and provides a place for documenting the specific requirements of inline assembly in naked functions. The implementation strategy was changed to emitting a global assembly block. In effect, an extern function ```rust extern "C" fn foo() { core::arch::naked_asm!("ret") } ``` is emitted as something similar to ```rust core::arch::global_asm!( "foo:", "ret" ); extern "C" { fn foo(); } ``` The codegen approach was chosen over the llvm naked function attribute because: - the rust compiler can guarantee the behavior (no sneaky additional instructions, no inlining, etc.) - behavior is the same on all backends (llvm, cranelift, gcc, etc) Finally, there is now an allow list of compatible attributes on naked functions, so that e.g. `#[inline]` is rejected with an error. The `#[target_feature]` attribute on naked functions was later made separately unstable, because implementing it is complex and we did not want to block naked functions themselves on how target features work on them. See also rust-lang/rust#138568. relevant PRs for these recent changes - rust-lang/rust#127853 - rust-lang/rust#128651 - rust-lang/rust#128004 - rust-lang/rust#138570 - ### Various historical notes #### `noreturn` [RFC 2972](https://github.com./rust-lang/rfcs/blob/master/text/2972-constrained-naked.md) mentions that naked functions > must have a body which contains only a single asm!() statement which: > iii. must contain the noreturn option. Instead of `asm!`, the current implementation mandates that the body contain a single `naked_asm!` statement. The `naked_asm!` macro is a heavily restricted version of the `asm!` macro, making it easier to talk about and document the rules of assembly in naked functions and give dedicated error messages. For `naked_asm!`, the behavior of the `asm!`'s `noreturn` option is implicit. The `noreturn` option means that it is UB for control flow to fall through the end of the assembly block. With `asm!`, this option is usually used for blocks that diverge (and thus have no return and can be typed as `!`). With `naked_asm!`, the intent is different: usually naked funtions do return, but they must do so from within the assembly block. The `noreturn` option was used so that the compiler would not itself also insert a `ret` instruction at the very end. #### padding / `ud2` A `naked_asm!` block that violates the safety assumption that control flow must not fall through the end of the assembly block is UB. Because no return instruction is emitted, whatever bytes follow the naked function will be executed, resulting in truly undefined behavior. There has been discussion whether rustc should emit an invalid instruction (e.g. `ud2` on x86) after the `naked_asm!` block to at least fail early in the case of an invalid `naked_asm!`. It was however decided that it is more useful to guarantee that `#[naked]` functions NEVER contain any instructions besides those in the `naked_asm!` block. # unresolved questions None r? ``@Amanieu`` I've validated the tests on x86_64 and aarch64
…ns, r=tgross35,Amanieu,traviscross Stabilize `naked_functions` tracking issue: rust-lang#90957 request for stabilization on tracking issue: rust-lang#90957 (comment) reference PR: rust-lang/reference#1689 # Request for Stabilization Two years later, we're ready to try this again. Even though this issue is already marked as having passed FCP, given the amount of time that has passed and the changes in implementation strategy, we should follow the process again. ## Summary The `naked_functions` feature has two main parts: the `#[naked]` function attribute, and the `naked_asm!` macro. An example of a naked function: ```rust const THREE: usize = 3; #[naked] pub extern "sysv64" fn add_n(number: usize) -> usize { // SAFETY: the validity of the used registers // is guaranteed according to the "sysv64" ABI unsafe { core::arch::naked_asm!( "add rdi, {}", "mov rax, rdi", "ret", const THREE, ) } } ``` When the `#[naked]` attribute is applied to a function, the compiler won't emit a [function prologue](https://en.wikipedia.org/wiki/Function_prologue_and_epilogue) or epilogue when generating code for this function. This attribute is analogous to [`__attribute__((naked))`](https://developer.arm.com/documentation/100067/0608/Compiler-specific-Function--Variable--and-Type-Attributes/--attribute----naked---function-attribute) in C. The use of this feature allows the programmer to have precise control over the assembly that is generated for a given function. The body of a naked function must consist of a single `naked_asm!` invocation, a heavily restricted variant of the `asm!` macro: the only legal operands are `const` and `sym`, and the only legal options are `raw` and `att_syntax`. In lieu of specifying operands, the `naked_asm!` within a naked function relies on the function's calling convention to determine the validity of registers. ## Documentation The Rust Reference: rust-lang/reference#1689 (Previous PR: rust-lang/reference#1153) ## Tests * [tests/run-make/naked-symbol-visiblity](https://github.com./rust-lang/rust/tree/master/tests/codegen/naked-fn) verifies that `pub`, `#[no_mangle]` and `#[linkage = "..."]` work correctly for naked functions * [tests/codegen/naked-fn](https://github.com./rust-lang/rust/tree/master/tests/codegen/naked-fn) has tests for function alignment, use of generics, and validates the exact assembly output on linux, macos, windows and thumb * [tests/ui/asm/naked-*](https://github.com./rust-lang/rust/tree/master/tests/ui/asm) tests for incompatible attributes, generating errors around incorrect use of `naked_asm!`, etc ## Interaction with other (unstable) features ### [fn_align](rust-lang#82232) Combining `#[naked]` with `#[repr(align(N))]` works well, and is tested e.g. here - https://github.com./rust-lang/rust/blob/master/tests/codegen/naked-fn/aligned.rs - https://github.com./rust-lang/rust/blob/master/tests/codegen/naked-fn/min-function-alignment.rs It's tested extensively because we do need to explicitly support the `repr(align)` attribute (and make sure we e.g. don't mistake powers of two for number of bytes). ## History This feature was originally proposed in [RFC 1201](rust-lang/rfcs#1201), filed on 2015-07-10 and accepted on 2016-03-21. Support for this feature was added in [rust-lang#32410](rust-lang#32410), landing on 2016-03-23. Development languished for several years as it was realized that the semantics given in RFC 1201 were insufficiently specific. To address this, a minimal subset of naked functions was specified by [RFC 2972](rust-lang/rfcs#2972), filed on 2020-08-07 and accepted on 2021-11-16. Prior to the acceptance of RFC 2972, all of the stricter behavior specified by RFC 2972 was implemented as a series of warn-by-default lints that would trigger on existing uses of the `naked` attribute; these lints became hard errors in [rust-lang#93153](rust-lang#93153) on 2022-01-22. As a result, today RFC 2972 has completely superseded RFC 1201 in describing the semantics of the `naked` attribute. More recently, the `naked_asm!` macro was added to replace the earlier use of a heavily restricted `asm!` invocation. The `naked_asm!` name is clearer in error messages, and provides a place for documenting the specific requirements of inline assembly in naked functions. The implementation strategy was changed to emitting a global assembly block. In effect, an extern function ```rust extern "C" fn foo() { core::arch::naked_asm!("ret") } ``` is emitted as something similar to ```rust core::arch::global_asm!( "foo:", "ret" ); extern "C" { fn foo(); } ``` The codegen approach was chosen over the llvm naked function attribute because: - the rust compiler can guarantee the behavior (no sneaky additional instructions, no inlining, etc.) - behavior is the same on all backends (llvm, cranelift, gcc, etc) Finally, there is now an allow list of compatible attributes on naked functions, so that e.g. `#[inline]` is rejected with an error. The `#[target_feature]` attribute on naked functions was later made separately unstable, because implementing it is complex and we did not want to block naked functions themselves on how target features work on them. See also rust-lang#138568. relevant PRs for these recent changes - rust-lang#127853 - rust-lang#128651 - rust-lang#128004 - rust-lang#138570 - ### Various historical notes #### `noreturn` [RFC 2972](https://github.com./rust-lang/rfcs/blob/master/text/2972-constrained-naked.md) mentions that naked functions > must have a body which contains only a single asm!() statement which: > iii. must contain the noreturn option. Instead of `asm!`, the current implementation mandates that the body contain a single `naked_asm!` statement. The `naked_asm!` macro is a heavily restricted version of the `asm!` macro, making it easier to talk about and document the rules of assembly in naked functions and give dedicated error messages. For `naked_asm!`, the behavior of the `asm!`'s `noreturn` option is implicit. The `noreturn` option means that it is UB for control flow to fall through the end of the assembly block. With `asm!`, this option is usually used for blocks that diverge (and thus have no return and can be typed as `!`). With `naked_asm!`, the intent is different: usually naked funtions do return, but they must do so from within the assembly block. The `noreturn` option was used so that the compiler would not itself also insert a `ret` instruction at the very end. #### padding / `ud2` A `naked_asm!` block that violates the safety assumption that control flow must not fall through the end of the assembly block is UB. Because no return instruction is emitted, whatever bytes follow the naked function will be executed, resulting in truly undefined behavior. There has been discussion whether rustc should emit an invalid instruction (e.g. `ud2` on x86) after the `naked_asm!` block to at least fail early in the case of an invalid `naked_asm!`. It was however decided that it is more useful to guarantee that `#[naked]` functions NEVER contain any instructions besides those in the `naked_asm!` block. # unresolved questions None r? ``@Amanieu`` I've validated the tests on x86_64 and aarch64
…oss35,Amanieu,traviscross Stabilize `naked_functions` tracking issue: rust-lang/rust#90957 request for stabilization on tracking issue: rust-lang/rust#90957 (comment) reference PR: rust-lang/reference#1689 # Request for Stabilization Two years later, we're ready to try this again. Even though this issue is already marked as having passed FCP, given the amount of time that has passed and the changes in implementation strategy, we should follow the process again. ## Summary The `naked_functions` feature has two main parts: the `#[naked]` function attribute, and the `naked_asm!` macro. An example of a naked function: ```rust const THREE: usize = 3; #[naked] pub extern "sysv64" fn add_n(number: usize) -> usize { // SAFETY: the validity of the used registers // is guaranteed according to the "sysv64" ABI unsafe { core::arch::naked_asm!( "add rdi, {}", "mov rax, rdi", "ret", const THREE, ) } } ``` When the `#[naked]` attribute is applied to a function, the compiler won't emit a [function prologue](https://en.wikipedia.org/wiki/Function_prologue_and_epilogue) or epilogue when generating code for this function. This attribute is analogous to [`__attribute__((naked))`](https://developer.arm.com/documentation/100067/0608/Compiler-specific-Function--Variable--and-Type-Attributes/--attribute----naked---function-attribute) in C. The use of this feature allows the programmer to have precise control over the assembly that is generated for a given function. The body of a naked function must consist of a single `naked_asm!` invocation, a heavily restricted variant of the `asm!` macro: the only legal operands are `const` and `sym`, and the only legal options are `raw` and `att_syntax`. In lieu of specifying operands, the `naked_asm!` within a naked function relies on the function's calling convention to determine the validity of registers. ## Documentation The Rust Reference: rust-lang/reference#1689 (Previous PR: rust-lang/reference#1153) ## Tests * [tests/run-make/naked-symbol-visiblity](https://github.com./rust-lang/rust/tree/master/tests/codegen/naked-fn) verifies that `pub`, `#[no_mangle]` and `#[linkage = "..."]` work correctly for naked functions * [tests/codegen/naked-fn](https://github.com./rust-lang/rust/tree/master/tests/codegen/naked-fn) has tests for function alignment, use of generics, and validates the exact assembly output on linux, macos, windows and thumb * [tests/ui/asm/naked-*](https://github.com./rust-lang/rust/tree/master/tests/ui/asm) tests for incompatible attributes, generating errors around incorrect use of `naked_asm!`, etc ## Interaction with other (unstable) features ### [fn_align](rust-lang/rust#82232) Combining `#[naked]` with `#[repr(align(N))]` works well, and is tested e.g. here - https://github.com./rust-lang/rust/blob/master/tests/codegen/naked-fn/aligned.rs - https://github.com./rust-lang/rust/blob/master/tests/codegen/naked-fn/min-function-alignment.rs It's tested extensively because we do need to explicitly support the `repr(align)` attribute (and make sure we e.g. don't mistake powers of two for number of bytes). ## History This feature was originally proposed in [RFC 1201](rust-lang/rfcs#1201), filed on 2015-07-10 and accepted on 2016-03-21. Support for this feature was added in [#32410](rust-lang/rust#32410), landing on 2016-03-23. Development languished for several years as it was realized that the semantics given in RFC 1201 were insufficiently specific. To address this, a minimal subset of naked functions was specified by [RFC 2972](rust-lang/rfcs#2972), filed on 2020-08-07 and accepted on 2021-11-16. Prior to the acceptance of RFC 2972, all of the stricter behavior specified by RFC 2972 was implemented as a series of warn-by-default lints that would trigger on existing uses of the `naked` attribute; these lints became hard errors in [#93153](rust-lang/rust#93153) on 2022-01-22. As a result, today RFC 2972 has completely superseded RFC 1201 in describing the semantics of the `naked` attribute. More recently, the `naked_asm!` macro was added to replace the earlier use of a heavily restricted `asm!` invocation. The `naked_asm!` name is clearer in error messages, and provides a place for documenting the specific requirements of inline assembly in naked functions. The implementation strategy was changed to emitting a global assembly block. In effect, an extern function ```rust extern "C" fn foo() { core::arch::naked_asm!("ret") } ``` is emitted as something similar to ```rust core::arch::global_asm!( "foo:", "ret" ); extern "C" { fn foo(); } ``` The codegen approach was chosen over the llvm naked function attribute because: - the rust compiler can guarantee the behavior (no sneaky additional instructions, no inlining, etc.) - behavior is the same on all backends (llvm, cranelift, gcc, etc) Finally, there is now an allow list of compatible attributes on naked functions, so that e.g. `#[inline]` is rejected with an error. The `#[target_feature]` attribute on naked functions was later made separately unstable, because implementing it is complex and we did not want to block naked functions themselves on how target features work on them. See also rust-lang/rust#138568. relevant PRs for these recent changes - rust-lang/rust#127853 - rust-lang/rust#128651 - rust-lang/rust#128004 - rust-lang/rust#138570 - ### Various historical notes #### `noreturn` [RFC 2972](https://github.com./rust-lang/rfcs/blob/master/text/2972-constrained-naked.md) mentions that naked functions > must have a body which contains only a single asm!() statement which: > iii. must contain the noreturn option. Instead of `asm!`, the current implementation mandates that the body contain a single `naked_asm!` statement. The `naked_asm!` macro is a heavily restricted version of the `asm!` macro, making it easier to talk about and document the rules of assembly in naked functions and give dedicated error messages. For `naked_asm!`, the behavior of the `asm!`'s `noreturn` option is implicit. The `noreturn` option means that it is UB for control flow to fall through the end of the assembly block. With `asm!`, this option is usually used for blocks that diverge (and thus have no return and can be typed as `!`). With `naked_asm!`, the intent is different: usually naked funtions do return, but they must do so from within the assembly block. The `noreturn` option was used so that the compiler would not itself also insert a `ret` instruction at the very end. #### padding / `ud2` A `naked_asm!` block that violates the safety assumption that control flow must not fall through the end of the assembly block is UB. Because no return instruction is emitted, whatever bytes follow the naked function will be executed, resulting in truly undefined behavior. There has been discussion whether rustc should emit an invalid instruction (e.g. `ud2` on x86) after the `naked_asm!` block to at least fail early in the case of an invalid `naked_asm!`. It was however decided that it is more useful to guarantee that `#[naked]` functions NEVER contain any instructions besides those in the `naked_asm!` block. # unresolved questions None r? ``@Amanieu`` I've validated the tests on x86_64 and aarch64
This is a tracking issue for the RFC "Constrained Naked Functions" (rust-lang/rfcs#2972).
The feature gate for the issue is
#![feature(naked_functions)]
.About tracking issues
Tracking issues are used to record the overall progress of implementation.
They are also used as hubs connecting to other relevant issues, e.g., bugs or open design questions.
A tracking issue is however not meant for large scale discussion, questions, or bug reports about a feature.
Instead, open a dedicated issue for the specific matter and add the relevant feature gate label.
Steps
#[naked]
naked_functions
#134213Unresolved Questions
None.
Implementation history
The text was updated successfully, but these errors were encountered: