Skip to content

Stabilize naked_functions #134213

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

folkertdev
Copy link
Contributor

@folkertdev folkertdev commented Dec 12, 2024

tracking issue: #90957
request for stabilization on tracking issue: #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:

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 or epilogue when generating code for this function. This attribute is analogous to __attribute__((naked)) 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

Interaction with other (unstable) features

fn_align

Combining #[naked] with #[repr(align(N))] works well, and is tested e.g. here

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, 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 naked attribute; these lints became hard errors in #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

extern "C" fn foo() {
    core::arch::naked_asm!("ret")
}

is emitted as something similar to

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 #138568.

relevant PRs for these recent changes

Various historical notes

noreturn

RFC 2972 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

@rustbot rustbot added A-run-make Area: port run-make Makefiles to rmake.rs PG-exploit-mitigations Project group: Exploit mitigations S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Dec 12, 2024
@rustbot
Copy link
Collaborator

rustbot commented Dec 12, 2024

Some changes occurred in src/doc/unstable-book/src/compiler-flags/sanitizer.md

cc @rust-lang/project-exploit-mitigations, @rcvalle

This PR modifies tests/run-make/. If this PR is trying to port a Makefile
run-make test to use rmake.rs, please update the
run-make port tracking issue
so we can track our progress. You can either modify the tracking issue
directly, or you can comment on the tracking issue and link this PR.

cc @jieyouxu

rust-analyzer is developed in its own repository. If possible, consider making this change to rust-lang/rust-analyzer instead.

cc @rust-lang/rust-analyzer

Some changes occurred in compiler/rustc_codegen_cranelift

cc @bjorn3

@traviscross traviscross added T-lang Relevant to the language team, which will review and decide on the PR/issue. S-waiting-on-documentation Status: Waiting on approved PRs to documentation before merging needs-fcp This change is insta-stable, so needs a completed FCP to proceed. I-lang-nominated Nominated for discussion during a lang team meeting. and removed T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Dec 13, 2024
@bors
Copy link
Collaborator

bors commented Dec 16, 2024

☔ The latest upstream changes (presumably #134395) made this pull request unmergeable. Please resolve the merge conflicts.

@folkertdev folkertdev force-pushed the stabilize-naked-functions branch from 6183807 to ed0d0b9 Compare December 18, 2024 21:05
@folkertdev folkertdev force-pushed the stabilize-naked-functions branch from ed0d0b9 to ae2fa18 Compare January 8, 2025 18:39
@tgross35 tgross35 added the T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. label Jan 9, 2025
@Amanieu
Copy link
Member

Amanieu commented Jan 13, 2025

r? lang

@rustbot rustbot assigned tmandry and unassigned Amanieu Jan 13, 2025
@Amanieu
Copy link
Member

Amanieu commented Jan 13, 2025

This probably needs a new lang FCP since the old one is probably outdated (the implementation of naked function has changed signficantly).

@tmandry
Copy link
Member

tmandry commented Jan 18, 2025

Thanks for the thorough report @folkertdev!

@rfcbot fcp merge

@rfcbot
Copy link
Collaborator

rfcbot commented Jan 18, 2025

Team member @tmandry has proposed to merge this. The next step is review by the rest of the tagged team members:

Concerns:

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!

cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns.
See this document for info about what commands tagged team members can give me.

@rfcbot rfcbot added proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels Jan 18, 2025
@tmandry
Copy link
Member

tmandry commented Jan 18, 2025

Actually, @rust-lang/libs-api does this need your FCP? I think the path of core::arch::naked_asm! is the only part that might.

@traviscross traviscross removed the PG-exploit-mitigations Project group: Exploit mitigations label Jan 27, 2025
jhpratt added a commit to jhpratt/rust that referenced this pull request Apr 19, 2025
…ttribute, r=tgross35,traviscross

Make `#[naked]` an unsafe attribute

tracking issue: rust-lang#138997

Per rust-lang#134213 (comment), the `#[naked]` attribute is now an unsafe attribute (in any edition).

This can only be merged when the above PRs are merged, I'd just like to see if there are any CI surprises here, and maybe there is early review feedback too.

r? `@traviscross`
@Amanieu
Copy link
Member

Amanieu commented Apr 19, 2025

The stabilization PR LGTM, so r=me.

@folkertdev folkertdev force-pushed the stabilize-naked-functions branch from 02cff1f to f087806 Compare April 19, 2025 14:24
@rustbot rustbot added the A-attributes Area: Attributes (`#[…]`, `#![…]`) label Apr 19, 2025
@rustbot
Copy link
Collaborator

rustbot commented Apr 19, 2025

Some changes occurred in compiler/rustc_passes/src/check_attr.rs

cc @jdonszelmann

ChrisDenton added a commit to ChrisDenton/rust that referenced this pull request Apr 19, 2025
…ttribute, r=tgross35,traviscross

Make `#[naked]` an unsafe attribute

tracking issue: rust-lang#138997

Per rust-lang#134213 (comment), the `#[naked]` attribute is now an unsafe attribute (in any edition).

This can only be merged when the above PRs are merged, I'd just like to see if there are any CI surprises here, and maybe there is early review feedback too.

r? ``@traviscross``
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Apr 20, 2025
Rollup merge of rust-lang#139753 - folkertdev:naked-function-unsafe-attribute, r=tgross35,traviscross

Make `#[naked]` an unsafe attribute

tracking issue: rust-lang#138997

Per rust-lang#134213 (comment), the `#[naked]` attribute is now an unsafe attribute (in any edition).

This can only be merged when the above PRs are merged, I'd just like to see if there are any CI surprises here, and maybe there is early review feedback too.

r? ``@traviscross``
@folkertdev folkertdev force-pushed the stabilize-naked-functions branch from f087806 to df8a3d5 Compare April 20, 2025 09:20
Copy link
Contributor Author

@folkertdev folkertdev left a comment

Choose a reason for hiding this comment

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

I believe everything is in now, I've just rebased on master.

@rustbot ready

Thanks everyone for the help here!

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Apr 20, 2025
Copy link
Contributor

@tgross35 tgross35 left a comment

Choose a reason for hiding this comment

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

LGTM as well

@greaka
Copy link
Contributor

greaka commented Apr 20, 2025

The only usage comment I have is that it would be nice if we could #[cfg] within naked_asm! somehow so small platform-specific changes don't mean the entire function needs to be duplicated.

Is there an issue to follow this specifically? It's already a problem when using global_asm.

@traviscross
Copy link
Contributor

Thanks for those reviews. Looks like we haven't quite finished reviewing the Reference PR, so we'll do that quickly and then move this along.

@traviscross
Copy link
Contributor

@rustbot labels -S-waiting-on-documentation

OK, the Reference PR is reviewed and approved, so this is OK to go forward. I've rereviewed the PR and the tests in light of the changes we had asked for, and @tgross35 and @Amanieu have reviewed as well, so let's...

@bors r=tgross35,Amanieu,traviscross rollup

@rustbot rustbot removed the S-waiting-on-documentation Status: Waiting on approved PRs to documentation before merging label Apr 21, 2025
@bors
Copy link
Collaborator

bors commented Apr 21, 2025

📌 Commit df8a3d5 has been approved by tgross35,Amanieu,traviscross

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Apr 21, 2025
@traviscross traviscross added relnotes Marks issues that should be documented in the release notes of the next release. I-lang-radar Items that are on lang's radar and will need eventual work or consideration. and removed I-lang-nominated Nominated for discussion during a lang team meeting. labels Apr 21, 2025
github-actions bot pushed a commit to rust-lang/rustc-dev-guide that referenced this pull request Apr 21, 2025
… r=tgross35,traviscross

Make `#[naked]` an unsafe attribute

tracking issue: rust-lang/rust#138997

Per rust-lang/rust#134213 (comment), the `#[naked]` attribute is now an unsafe attribute (in any edition).

This can only be merged when the above PRs are merged, I'd just like to see if there are any CI surprises here, and maybe there is early review feedback too.

r? ``@traviscross``
jieyouxu added a commit to jieyouxu/rust that referenced this pull request Apr 21, 2025
…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
bors added a commit to rust-lang-ci/rust that referenced this pull request Apr 21, 2025
Rollup of 12 pull requests

Successful merges:

 - rust-lang#134213 (Stabilize `naked_functions`)
 - rust-lang#139795 (Clarify why SGX code specifies linkage/symbol names for certain statics)
 - rust-lang#139981 (Don't compute name of associated item if it's an RPITIT)
 - rust-lang#140036 (Advent of `tests/ui` (misc cleanups and improvements) [4/N])
 - rust-lang#140047 (remove a couple clones)
 - rust-lang#140052 (Fix error when an intra doc link is trying to resolve an empty associated item)
 - rust-lang#140074 (rustdoc-json: Improve test for auto-trait impls)
 - rust-lang#140076 (jsondocck: Require command is at start of line)
 - rust-lang#140077 (Construct OutputType using macro and print [=FILENAME] help info)
 - rust-lang#140081 (Update `libc` to 0.2.172)
 - rust-lang#140091 (build_helper: try to rename dir before delete)
 - rust-lang#140107 (rustc-dev-guide subtree update)

r? `@ghost`
`@rustbot` modify labels: rollup
ChrisDenton added a commit to ChrisDenton/rust that referenced this pull request Apr 21, 2025
…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
bors added a commit to rust-lang-ci/rust that referenced this pull request Apr 21, 2025
…enton

Rollup of 11 pull requests

Successful merges:

 - rust-lang#134213 (Stabilize `naked_functions`)
 - rust-lang#139711 (Hermit: Unify `std::env::args` with Unix)
 - rust-lang#139795 (Clarify why SGX code specifies linkage/symbol names for certain statics)
 - rust-lang#140036 (Advent of `tests/ui` (misc cleanups and improvements) [4/N])
 - rust-lang#140047 (remove a couple clones)
 - rust-lang#140052 (Fix error when an intra doc link is trying to resolve an empty associated item)
 - rust-lang#140074 (rustdoc-json: Improve test for auto-trait impls)
 - rust-lang#140076 (jsondocck: Require command is at start of line)
 - rust-lang#140107 (rustc-dev-guide subtree update)
 - rust-lang#140111 (cleanup redundant pattern instances)
 - rust-lang#140118 ({B,C}Str: minor cleanup)

r? `@ghost`
`@rustbot` modify labels: rollup
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-attributes Area: Attributes (`#[…]`, `#![…]`) A-run-make Area: port run-make Makefiles to rmake.rs disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. I-lang-radar Items that are on lang's radar and will need eventual work or consideration. needs-fcp This change is insta-stable, so needs a completed FCP to proceed. PG-exploit-mitigations Project group: Exploit mitigations relnotes Marks issues that should be documented in the release notes of the next release. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-lang Relevant to the language team, which will review and decide on the PR/issue. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. to-announce Announce this issue on triage meeting
Projects
None yet
Development

Successfully merging this pull request may close these issues.