Skip to content

Conversation

folkertdev
Copy link
Contributor

@folkertdev folkertdev commented Dec 1, 2024

tracking issue: rust-lang/rust#90957
earlier version: #1153

Pending on rust-lang/rust#128004. Once merged, we'll move for stabliziation.

I'm working off of the original PR to the reference, written 2+ years ago when the reference was less strict. I suspect some refinement and editing will be needed here to satisfy the quality requirements of the spec, and update the text to accurately reflect the current state and the exact guarantees/requirements.

Stabilization PR:

cc @bstrie @traviscross @Amanieu @bjorn3

- The compiler cannot assume that the instructions in the asm are the ones that will actually end up executed.
- This effectively means that the compiler must treat the `naked_asm!` as a black box and only take the interface specification into account, not the instructions themselves.
- Runtime code patching is allowed, via target-specific mechanisms.
- However there is no guarantee that each `naked_asm!` directly corresponds to a single instance of instructions in the object file: the compiler is free to duplicate or deduplicate `naked_asm!` blocks.
Copy link
Member

Choose a reason for hiding this comment

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

This is not true, naked functions cannot be duplicated/merged, unlike asm!.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

and reading this over, in this case it seems important that we do actually guarantee (and hence the compiler can assume) that the instructions in the naked_asm! invocation are exactly the ones that will be executed. or is that too strict?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think that poses problems on SPIR-V or NVPTX targets. I seem to recall that the loader just inlines the functions at the Shader Assembly level.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@chorman0773 just to be sure, you're referring to Amanieu's comment right?

What we do in rustc (or well, we will once that PR makes it through the queue) is that a naked function

#[naked]
extern "C" fn foo() {}

is emitted as something similar to

core::arch::global_asm!( 
    "foo:",
    "ret"
);

extern "C" {
    fn foo();
}

and we're relying on the compiler (rustc, llvm) not duplicating that bit of global assembly. I suspect we already rely on that in general, because global assembly can define symbols today.

If you still think this is problematic, how could we verify the behavior of this new codegen strategy for the targets you list?

Copy link
Member

Choose a reason for hiding this comment

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

and reading this over, in this case it seems important that we do actually guarantee (and hence the compiler can assume) that the instructions in the naked_asm! invocation are exactly the ones that will be executed. or is that too strict?

No, they may not be the same instructions that are executed since you can still do runtime patching. We only guarantee that assembly code only appears once in the object file for the purposes of symbols.

@ehuss ehuss added S-waiting-on-stabilization Waiting for a stabilization PR to be merged in the main Rust repository S-waiting-on-review Status: The marked PR is awaiting review from a maintainer labels Dec 5, 2024
@rustbot

This comment has been minimized.

@folkertdev folkertdev force-pushed the stabilize-naked-functions branch from b2ee83c to 1a8abe7 Compare January 14, 2025 21:16
@rustbot

This comment has been minimized.

@folkertdev folkertdev force-pushed the stabilize-naked-functions branch from 1a8abe7 to 7fdadec Compare January 29, 2025 09:00
@JoelMarcey JoelMarcey self-requested a review January 30, 2025 16:36
@rustbot

This comment has been minimized.

@folkertdev folkertdev force-pushed the stabilize-naked-functions branch 2 times, most recently from d1a523d to 1caf564 Compare February 13, 2025 21:00
@folkertdev folkertdev force-pushed the stabilize-naked-functions branch 2 times, most recently from f92f75f to 54ddde1 Compare March 7, 2025 19:28
Comment on lines 1382 to 1445
# #[cfg(target_arch = "x86_64")] {
#[naked]
extern "C-unwind" fn naked_function() {
unsafe {
core::arch::naked_asm!(
".cfi_startproc",
"push rbp",
".cfi_def_cfa_offset 16",
".cfi_offset rbp, -16",
"mov rbp, rsp",
".cfi_def_cfa_register rbp",
"",
"call {function}",
"",
"pop rbp",
".cfi_def_cfa rsp, 8",
"ret",
".cfi_endproc",
function = sym function_that_panics,
)
}
}
extern "C-unwind" fn function_that_panics() {
panic!("unwind!");
}
# }
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think I can currently run this because #[naked] is still unstable. So reminder to self: update this before merging.

cc @traviscross

Copy link
Contributor

@traviscross traviscross Mar 8, 2025

Choose a reason for hiding this comment

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

We won't merge this anyway until the stabilization lands, so you can just update it and leave the CI red until then (add the feature flag and test it locally though). That's what we normally do.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Locally I still even get errors like this

Couldn't compile the test.
---- inline-assembly.md - Inline_assembly::Options (line 1360) stdout ----
error[E0658]: label operands for inline assembly are unstable
 --> inline-assembly.md:1364:32
  |
6 |       core::arch::asm!("jmp {}", label {
  |  ________________________________^
7 | |         println!();
8 | |     }, options(noreturn));
  | |_____^
  |
  = note: see issue #119364 <https://github.com/rust-lang/rust/issues/119364> for more information

with these versions in the reference folder (so I don't think there is a rustup override active)

> cargo --version
cargo 1.88.0-nightly (d811228b1 2025-04-15)
> rustc --version
rustc 1.88.0-nightly (191df20fc 2025-04-18)

That feature has been stable on nightly for a while, so I must be missing something. Anyway, I believe the current code to be correct, and CI will catch it before merge if there are minor issues.

Copy link
Contributor

@traviscross traviscross Apr 19, 2025

Choose a reason for hiding this comment

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

I've had trouble with overrides too on the Reference for reasons I haven't yet worked out. Perhaps if you rustup default nightly (or rustup default stage1 or whatnot) it will work for you.

@rustbot

This comment has been minimized.

@folkertdev folkertdev force-pushed the stabilize-naked-functions branch from 54ddde1 to 81ad95f Compare March 18, 2025 09:49
The unsafe code guidelines document describes itself currently as
largely abandoned and indicates that those points that have found
consensus are documented in the Reference.  Let's not then normatively
cite that other document.

Let's also remove a line about "these rules do not apply..." where
"these" changed meaning when this line was copied from elsewhere.  In
the original, "these" meant rules about `readonly` and `nomem`,
whereas here, it would have seemed to refer to the rules in the UCG,
and that wouldn't make sense.
Copy link
Contributor

@traviscross traviscross left a comment

Choose a reason for hiding this comment

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

OK, with the changes I've pushed, this look OK to me, so we can approve this to unblock the stabilization.

@traviscross traviscross removed the S-waiting-on-review Status: The marked PR is awaiting review from a maintainer label Apr 21, 2025
We demonstrate how to correctly unwind from a naked function.  The
assembler directives and boilerplate for this may be unfamiliar to
people, so let's annotate this example heavily and add links to
further resources.

We'll use the `sysv64-unwind` ABI rather than `C-unwind` just to make
things a bit more unambiguous.
@folkertdev folkertdev marked this pull request as ready for review April 22, 2025 11:49
@folkertdev folkertdev closed this Apr 22, 2025
@folkertdev folkertdev reopened this Apr 22, 2025
@folkertdev
Copy link
Contributor Author

Those final changes look good to me. The feature has been stabilized and CI passes here, so I think that should be everything.

For naked functions, let's break out the rules for callee and caller
saved registers and name the rule identifiers more clearly.

For the caller saved registers, let's drop the caveat about "even if
they are not used for the return value", as it doesn't really add
anything to the rule.
@traviscross traviscross force-pushed the stabilize-naked-functions branch from 4d17358 to aca530a Compare April 22, 2025 18:52
@traviscross traviscross added this pull request to the merge queue Apr 22, 2025
@traviscross
Copy link
Contributor

Thanks to @folkertdev for pushing this forward.

@traviscross traviscross removed the S-waiting-on-stabilization Waiting for a stabilization PR to be merged in the main Rust repository label Apr 22, 2025
Merged via the queue into rust-lang:master with commit ff6252f Apr 22, 2025
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants