-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Add support for naked functions. #1201
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
Conversation
👍 This would allow using only Rust + inline assembly in a kernel. |
How does this interact with the calling convention? I recently looked into writing some inline assembly, using If all this does is let us replace the contents of an I'm inclined to suggest that |
This doesn't seem like a terribly good idea, LLVM lacked this for a very long time due to the undefined and extremely iffy semantics involved, essentially the only thing that can safely be done in a naked function is using a single asm block. LLVM already has had support for module-level assembly blocks as long as I can remember. Although I wouldn't let any remotely complicated hand-written code get within 50 feet of LLVMs built-in assembler either (it tends to be somewhat broken) |
I think you're right that anything but parameterless functions returning
Without Rust support though, that doesn't get us very far. The advantage of putting this directly on functions is that we allow the compiler to generate a function definition, including name mangling. Despite the much greater implementation complexity, I'm coming around to the |
@tari: My point wasn't "you can't write naked functions that take arguments", it was "you can't write naked functions that take arguments using the undefined I think the good solution is to make sure that naked functions aren't "desugared" into
|
Either way, the compiler could provide name mangling for module-level assembly blocks, which would be much saner. |
Isn't name mangling seperate from the ABI already in rust, ie. One problem with For this reason, I think it would be better to leave Finally, there may be cases where the naked function doesn't follow any standard ABI, in which case it shouldn't be callable at all from rust code. This "unspecified" ABI could be selected via |
The trouble with that approach I see is that it becomes impossible to safely call such a naked function from Rust. We could choose to forbid native rust calls to such a function, but that seems to me like an unusual exception to the rule that all declared functions are callable.
Right; I started conflating the goal and means a bit here. Clarifying: my ultimate goal is to support writing interrupt handlers in Rust-only. The proposed means to that is introducing naked functions which allow the programmer to use an arbitrary calling convention. As Changing this approach would have the implication that some calls to functions defined in Rust become wrong because they assume a different calling convention- a hypothetical Given the previous points, the simplest approach to supporting arbitrary ABIs appears to be implementing them in the compiler. This is much less flexible than supporting naked functions, but permits more efficient code generation since the compiler has detailed knowledge of what the system is doing. For the motivating use case this could be Addition of calling conventions doesn't preclude a generic mechanism for naked functions, but it does sidestep the current issues involved in making naked functions useful. |
A naked function is no less safe to call than any other non-local I get the feeling that we're starting to talk across purposes, here, so let's clarify. I'm talking about something like: #[cfg(target_arch="x86")]
extern "C" fn add_two(a: i32, b: i32) -> i32 {
#![naked]
asm!(r#"
mov eax, [esp+4]
mov ecx, [esp+8]
add eax, ecx
"#)
}
fn main() {
assert_eq!(add_two(4, 6), 10);
} Unless I've got the assembler wrong (it's been a while), the above should be perfectly safe to call. It's a function that uses the C ABI... that it's written in assembler and doesn't have the standard function prelude is just an implementation detail the user doesn't need to worry about. I mean, |
The difference is that the only reason to use a naked function is when the compiler does not understand the ABI you need to use and is thus virtually guaranteed to generate code that will do something unexpected (and wrong) if you try to call it. You can implement a naked function that uses the C ABI, but there's no reason to do so because the compiler already understands how to deal with that for you. |
@tari That's simply not true - there are many reasons to require a naked function even when using an ABI that the compiler understands. |
Can you provide some examples of situations you'd want to do so? The way I see it, naked functions are useful to fill holes in the compiler's ABI support and I don't see the point of using one when the compiler is capable of doing what you need. |
Sometimes you can implement a method more efficiently than the compiler's default prolog/epilog would allow. For example, I needed to write a function which returned the address of the caller. With a naked function, this boils down to two instructions: mov eax, [ebp+4]
ret There's just no way to generate code like that without getting rid of the default prolog and epilog. |
@Diggsey While specific stack layout (e.g. caller address being at #![feature(asm)]
pub fn myfunc() -> u32 {
let ret: u32;
unsafe { asm!("mov $0, [ebp+4]" : "=r"(ret) ::: "intel"); }
return ret;
}
// yes, I'm compiling this on x86_64, so it won't ever work like this anyways but it really doesn't matter for this example
And there you go. Exactly what you wanted, without a naked function. |
It seems we have two somewhat distinct use cases for naked functions, where I only had the first in mind while writing this RFC:
Neither of these works well with the current proposal, because the ABI of function calls generated by the compiler is unspecified. For a compiler-generated call to such a function, we should require that the ABI in use be well-defined (specifically it must not use the Rust ABI, and we may want to restrict it to If the calling convention of a naked function which is called from Rust code is constrained to be well-defined, the problems are purely in implementation- @main-- that may be technically possible, but it's too fragile for me to be comfortable encouraging such a thing. We can make the static guarantees of such a function stronger by allowing it to be declared as naked without affecting the rest of the language, so I believe we should. |
I agree that especially for things like interrupt handlers, naked functions are simply a necessity. Of course one could try and hack around that by calling into an embedded inline asm block, but that's far from perfect. I do have doubts regarding ABI emulation (providing functions in a specific ABI without compiler support): Every function needs its own trampoline, right? So one would probably write a macro to create all those trampolines which ... surprisingly isn't even that messy, but still less pretty than it could be ( When calling a method, we need to know how. In case of a "standard" naked function, this gets us into a funny situation: Just like with any normal function, we're supposed to use the Rust ABI which is fine for us - but at the same time we're sure that they (callee) can never handle this correctly due to that ABI being undefined. I'd suggest making those functions uncallable and forcing them to be parameterless. On the other hand, when a naked function's ABI has a well-known definition (like The other difficult part are local variables. Should you write "heavy" rust code within naked functions? Probably not. But it should definitely be possible within certain limits. Why else would you use Rust if you could just write your function in plain asm (much better tooling than inline asm)? Straight up banning locals is not a great solution, but since the compiler can't really reserve stack space either (naked --> no prolog) something like MSVC's __LOCAL_SIZE is probably inevitable. The really ugly part about that particular approach is that the compiler is forced to emit even useless prologs and epilogs (when no stack spilling is required). So one can either sacrifice performance by having them or sacrifice non-optimized builds altogether since rustc (like many compilers) likes to just hold everything on the stack and then rely heavily on the optimizer to eliminate these useless stack operations, simply resulting in broken code without that. |
Sorry for this, but... is this a problem that needs solving? I do a lot of systems programming, and do my best to avoid inline assembly where I can. Usually, what I'll do instead (especially for something like an interrupt handler), is write an assembly file and have it call out to a C-ABI routine to get a trampoline to more maintainable code. I don't yet see how |
@aidancully arbitrary codegen driven by Rust code, basically. static HANDLERS: [AtomicPtr<()>; 256] = [AtomicPtr::new(); 256];
#[naked]
unsafe fn handle_interrupt<F: Fn()>(number: u8) {
(*(HANDLERS[number as usize].load(Relaxed) as *const F))();
asm!("iret");
} |
Are there links to LLVM discussion on this topic? |
I haven't found any meaningful LLVM discussion on it. Support was added in 2009, r76198, which may be a good starting point for searching. |
Also expand motivation beyond ISRs per RFC discussion.
@eddyb That code is most certainly broken. If the compiler ever spills a register, you're fucked. Since it's also an interrupt handler, it should avoid clobbering registers, which is impossible to do efficiently in any way that will please LLVM. In general the only way you're ever going to get the correct output is by having a single asm block within the function, which is just a hacky version of module-level assembly. |
While the RFC currently doesn't address this issue it's not a problem with naked functions in general as solving it is possible (and probably necessary; see my previous comment). |
@eddyb For what it's worth, I find that type of use plausible as a motivator, but I also worry that it might be very challenging to make static HANDLERS: [AtomicPtr<()>; 256] = [AtomicPtr::new(); 256];
#[naked]
unsafe fn handle_interrupt<F: Fn()>(number: u8)
{
// F::ABI's static functions are #[naked] #[inline].
F::ABI::create_calling_env();
(*(HANDLERS[number as usize].load(Relaxed) as *const F))();
F::ABI::destroy_calling_env();
asm!("iret");
} But if this sort of thing is necessary to safely support generic naked functions, it'd probably need to be reflected in the RFC. (Note that I don't think the whole change would need to land at once, the initial patch sounds pretty small and may be acceptable in the short term. But the design space in which the feature would be used probably needs to be explored better... I think there's a significant risk that, even though |
@aidancully if you don't generate multiple monomorphizations, you need to use indirect calls, which might be a measurable cost during interrupt handling - but it is a micro-optimization and I could very well be wrong about it. |
If I understand the current tack of the discussion now, the main concern is that the effect of writing code that is not inline assembly in a naked function is unpredictable. The correctness of the A way to ask the compiler how much space it needs for locals would permit a solution, but there's no mechanism to enable that in LLVM. I see a way forward in having an LLVM intrinsic function that is guaranteed to lower to a constant load representing the necessary size of locals, but I think such a significant change is beyond the scope of this proposal. With the |
Both cases could be accommodated by putting support for Rust statements in naked functions behind a feature gate; something like |
In a recent lang subteam meeting, we decided to close this PR. This RFC seems to have a lot in common with #55, which was closed by @brson with the following rationale:
The situation seems not to have changed very much -- basically it seems a bit premature to be introducing these sorts of constructs. The concerns about running Rust code in naked functions seem particularly salient. (Taking off my lang subteam hat for a moment and speaking personally, I think I would prefer to address this by writing naked functions in pure assembly and linking them in with LTO -- or having a variant on inline assembly that generates an entire function.) |
Given that rust is meant to be a system level programming language, I think it is needed to have this feature (or a similar on) in rust. Through it is needed for low level tasks for many people given that this feature is not needed or even bad style in less low level code I would propose that (if available in stable) there is per default lint like Also even through module level asm seems to* be able to emulate naked fn's I think naked fn's are much clearer for use cases like interrupts. (* I might have missed something, but naked fn's can contains (some) "normal" rust code, but module level asm can't, or?) |
@Naicode Naked functions have to be assembly-only. |
Ok, so module level asm and naked functions most likely can emulate each other. Hm, I't might be able to implement platform-specific interrupt handling by combining macros with naked functions, leaving naked functions still there for the other use cases. |
@Naicode You would want to implement the whole Rust language in macros? |
@eddyb No! that would be horribly ;=) What I meant, is that, if the naked fn's can only contain asm, you would either write the complete ISR in assembly or delegate to a rust-fn at some point. This boiler part could be be written as a macro... e.g. the example from the rfc: #[naked]
#[cfg(target_arch="x86")]
unsafe fn isr_3() {
asm!("pushad
call increment_breakpoint_count
popad
iretd" :::: "volatile");
intrinsics::unreachable();
} could be written like: delegate_isr_3!(increment_breakpoint_count) Through in the end having a rust native ISR ABI might be more performant/useful Also you could pass a codeblock to a macro, but it probably wouldn't be a good idea to use it without wrapping it in a function because it might contain a return statement (and possible other "bad" thinks), but you could also have a way to forbid return statements in code block passed to macro, well that is a different topic. |
Huzzah! The @rust-lang/lang team has decided to accept this RFC. As previously stated, this is being accepted on a particularly experimental basis, especially with respect to the semantics (or lack thereof) of Rust code embedded in a naked function. One plausible route for stability would be to stabilize the |
Tracking issue rust-lang/rust#32408. |
Thanks, thanks, thanks, @rust-lang/lang. |
PR submitted: rust-lang/rust#32410 |
Add support for naked functions See rust-lang/rfcs#1201 (comment) This PR adds `#[naked]` for marking naked functions.
…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
…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
Rendered.
[edited to link to the final rendered version]