Skip to content
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

Tracking issue for naked fns (RFC #1201) #32408

Closed
nikomatsakis opened this issue Mar 21, 2016 · 75 comments
Closed

Tracking issue for naked fns (RFC #1201) #32408

nikomatsakis opened this issue Mar 21, 2016 · 75 comments
Labels
A-naked Area: `#[naked]`, prologue and epilogue-free, functions, https://git.io/vAzzS B-RFC-implemented Blocker: Approved by a merged RFC and implemented. B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. disposition-close This PR / issue is in PFCP or FCP with a disposition to close it. finished-final-comment-period The final comment period is finished for this PR / Issue. S-tracking-design-concerns Status: There are blocking ❌ design concerns. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@nikomatsakis
Copy link
Contributor

nikomatsakis commented Mar 21, 2016

This is the tracking issue for rust-lang/rfcs#1201.

Note that this is intended as a (particularly) experimental feature.

Feedback on its design is required, as well as comparisons with global asm.

@nikomatsakis nikomatsakis added B-RFC-approved Blocker: Approved by a merged RFC but not yet implemented. T-lang Relevant to the language team, which will review and decide on the PR/issue. B-unstable Blocker: Implemented in the nightly compiler and unstable. labels Mar 21, 2016
@jackpot51
Copy link
Contributor

This issue was partially addressed by #29189

@jackpot51
Copy link
Contributor

#32410 is an up to date implementation

@alexcrichton alexcrichton removed the B-RFC-approved Blocker: Approved by a merged RFC but not yet implemented. label Mar 23, 2016
@ranma42
Copy link
Contributor

ranma42 commented Mar 26, 2016

It might be a little late to point it out, but the RFC does not say anything about the interaction between naked functions and unwinding/panics.

@nagisa nagisa added the A-naked Area: `#[naked]`, prologue and epilogue-free, functions, https://git.io/vAzzS label Jun 2, 2016
@nikomatsakis
Copy link
Contributor Author

Note that global-asm has also been added, which overlaps somewhat with naked fns.

@nrc nrc added the B-RFC-implemented Blocker: Approved by a merged RFC and implemented. label Aug 29, 2016
@mark-i-m
Copy link
Member

So how exactly do experimental features get stabilized? This is an incredibly useful feature for building an OS, and I would love to see it move forward :)

@nikomatsakis
Copy link
Contributor Author

@mark-i-m well, if we retrofit this into the "experimental RFC" process that we are experimenting with (so much experimenting!), then the next step would be to take the lessons we've learned from having the feature around and write-up a new RFC that lays out the:

  • final design of the feature, and in particular the various tricky cases and how we decided to resolve them
  • talks about experience in the wild
  • etc

and then we would proceed as normal.

In the case of naked functions, I think if anything my doubts have grown more grave, not less. In particular, I still don't think we can say much with confidence about how Rust code embedded in naked functions is expected to be compiled. Right now it's all pretty darn unspecified, iirc. I'd be interested to see some kind of data points for whether all naked fns in the wild use purely inline assembly, or whether they embed Rust code, and if so, what Rust code they embed (maybe we can define some kind of sensible subset)?

@mark-i-m
Copy link
Member

@nikomatsakis Here is some code I wrote last weekend for an OS kernel: https://gist.github.com/mark-i-m/361cbcc39769f965b1c419091b9cbf4f

It is mostly assembly, but it does have Rust mixed in. Specifically, it has function calls not just to other naked or inlined functions, but also to normal Rust functions, such as here.

In particular, I still don't think we can say much with confidence about how Rust code embedded in naked functions is expected to be compiled.

Personally, my expectation is that it should compile just like it normally would -- just the prologue/epilogue are left out. For example,

extern "C" fn foo(bar: usize) -> usize {
    bar << 1
}

generates

_ZN10playground3foo17h002f6b2acb4d5b2dE:
.Lfunc_begin2:
	.loc	1 2 0
	.cfi_startproc
	pushq	%rbp
.Ltmp12:
	.cfi_def_cfa_offset 16
.Ltmp13:
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
.Ltmp14:
	.cfi_def_cfa_register %rbp
	movq	%rdi, -16(%rbp)
.Ltmp15:
	.loc	1 2 0 prologue_end
	movq	-16(%rbp), %rdi
	movq	%rdi, -8(%rbp)
.Ltmp16:
	.loc	1 3 0
	movq	-8(%rbp), %rdi
	shlq	$1, %rdi
	movq	%rdi, -24(%rbp)
	.loc	1 4 0
	movq	-24(%rbp), %rax
	popq	%rbp
	retq

I imagine the naked version would simply be this (I didn't adjust the offsets on the stack):

_ZN10playground3foo17h002f6b2acb4d5b2dE:
.Ltmp15:
	.loc	1 2 0 prologue_end
	movq	-16(%rbp), %rdi
	movq	%rdi, -8(%rbp)
.Ltmp16:
	.loc	1 3 0
	movq	-8(%rbp), %rdi
	shlq	$1, %rdi

@mark-i-m
Copy link
Member

Oh, and irq_common is another great example! It has a lot of stuff

  • naked
  • inlined
  • inline assembly with outputs to Rust variables, including a pointer to a Rust-defined struct
  • calls a normal Rust function
  • returns !
  • has a panic which should never be called.

@Mark-Simulacrum Mark-Simulacrum added the C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. label Jul 22, 2017
@mark-i-m
Copy link
Member

I guess since embedded is a focus in 2018, this will be revived soon.

One thing to note is that this feature is pretty useless to stabilize before inline asm 😛

@dancrossnyc
Copy link

It would be nice to see some movement on naked functions; I'm using them for e.g. interrupt handlers and the like in kernel-level code. Naked functions are one of the only ways to inject e.g. Rust constants into things like interrupt and syscall handlers. Yes, one can do that via inline assembly in "normal" functions, but there the preamble and epilogue can trash things you'd like to preserve on your stack (if you even have one! Consider the behavior of the syscall instruction on x86_64: the CPU switches into kernel mode and start executing whatever the LSTAR MSR points at, but at that point you don't even have a kernel stack!).

Module level assembler doesn't really work here since you can't inject the value of a const into the text presented to the "assembler". If I want to use the value of a Rust constant in assembler, I've pretty much got to pass it as an immediate in an inline assembler statement a la 'asm!()'.

We're getting concerned about the dependency on unstable features and ties to the nightly compiler to get access to those unstable features, and what production people might have to say about that (which could potentially scuttle our entire Rust effort). Put another way, it sure would be nice to be able to build a kernel using only stable Rust.

@Amanieu
Copy link
Member

Amanieu commented Apr 18, 2019

I think the general consensus is that we are happy to have naked functions, but there is no point in stabilizing them before inline asm since they are useless without it.

@mark-i-m
Copy link
Member

Lol, that sounds like a challenge to find something you can do with naked functions without assembly 😆

#[naked]
fn hehehe() -> ! {
  loop {} // No inline asm here!
}

More seriously, I think naked functions can actually be useful apart from inline-asm. I was thinking about what specifically naked means... I think it means the following:

  • The "nakedness" of a function is invisible to the caller. The caller must obey the calling convention but doesn't have any other special responsibilities. Among other things, this means that the caller must keep its stack pointer up to date (or at least, it should point to the top of the stack at the time of the naked function call).
  • The naked function does not have a function prologue or epilogue. If it wants stack space, it has to make it using inline asm.
  • Using stack-allocated locals (e.g. let-bindings) in a naked function is unspecified behavior. I suggest we prohibit it for now.
  • The naked function promises to obey all calling convention contracts with its caller (e.g. not clobbering callee-saved registers or the caller's stack frame).
  • Naked functions can safely make function calls to other functions. Their arguments are pushed to the stack before the call and popped afterwards, just like any normal function call.

In light of this, the following examples seem like they would be valid:

#[no_mangle]
fn unsafe extern "x86-interrupts" do_pic_irq(irq_stack: IrqStackFrame) {
  sched.timer(&irq_stack);
}
#[no_mangle]
fn unsafe extern "x86-interrupts" do_page_fault(exception_stack: ExceptionStackFrame) {
  CURRENT_PROCESS.mm.handle(&exception_stack);
}

@main--
Copy link
Contributor

main-- commented May 8, 2019

Naked functions are mostly equivalent to global asm. Notable exceptions:

  • Executing Rust code
  • using Rust constants

Nothing else that I am aware of.

When it comes to constants, I see no reason why global asm shouldn't support this as well.

Executing Rust code is the really powerful part. But it's very tricky due to the Rust ABI not being specified (#600). Let's say rust-abi suddenly declares that on x86 eax should always be 42 (and the compiler uses this for arithmetic operations): obviously the handwritten prologue of a of a naked function would need to make sure that this invariant holds before running any Rust code - or risk UB.
But since it can't know that it needs to do this (ABI is unspecified) don't we have to assume that any Rust code inside a naked function is UB?

@mark-i-m
Copy link
Member

mark-i-m commented May 8, 2019

I think it makes sense to just enforce that all naked fns have to be extern C.

@main--
Copy link
Contributor

main-- commented May 9, 2019

I think it makes sense to just enforce that all naked fns have to be extern C.

I'm not even sure if this is sufficient. What about arguments? Obviously declaring function parameters is out of the question - you would have to do it in your asm prologue instead. But this opens up the interesting problem that you can no longer have a volatile inline asm block as the first thing in the function: you need to at least declare (and potentially initialize?) the variables that are going to hold your parameters first. Is this guaranteed to be safe? Given that Rust does not have a register keyword like C I don't see why the compiler shouldn't be allowed to stack-allocate space for a variable prior to the prologue in this case. To avoid this, compilers typically don't allocate stack space in naked functions at all, instead relying on the user-supplied prologue to do this as well. But how would you know exactly how many bytes to reserve? Who specifies that this is always directly measured from esp? I think this is no really about calling conventions but rather about the very specific interaction between a naked function and the compiler-generated code inside of it.

I get the feeling that naked functions are a minefield of UB and footguns that should be avoided. Perhaps custom ABIs / calling conventions could be a better way to solve the same problems?

@mark-i-m
Copy link
Member

mark-i-m commented May 9, 2019

Obviously declaring function parameters is out of the question - you would have to do it in your asm prologue instead.

I didn’t followed this point. The arguments are not on the callee’s stack frame; they are on the caller’s stack frame. As long as the caller obeys the calling convention, what’s the problem?

I get the feeling that naked functions are a minefield of UB and footguns that should be avoided. Perhaps custom ABIs / calling conventions could be a better way to solve the same problems?

I think that would lead to a proliferation of custom calling conventions. Moreover fully specifying a calling convention sounds like a pain.

@Mark-Simulacrum Mark-Simulacrum removed the I-lang-nominated Nominated for discussion during a lang team meeting. label Jan 25, 2022
@bstrie
Copy link
Contributor

bstrie commented Jan 28, 2022

@ds84182 That seems useful, but it seems like it would be fully backwards-compatible to stabilize naked_functions as-is and only later extend it to allow multiple asm! blocks, yes? IOW, whether or not your proposal is accepted, it doesn't appear to impede the consideration of this attribute for stabilization.

@npmccallum
Copy link
Contributor

@bstrie Correct. The CNF RFC explicitly states: "This definition may be overly strict. There is certainly some code that would work without this. ... It might also be possible to reasonably ease the constraints over time."

From my perspective, I'd like to get something overly restrictive available for use in stable. Over time we can relax those restrictions or add features. But I don't want to let the perfect be the enemy of the good.

@mark-i-m
Copy link
Member

One thing to consider: is any of the requirements on CNF not relaxable? For example, is there any future compatibility hazard in the noreturn requirement that would, say, change what kind of code is emitted after a naked function or change the state of the stack at different points in the function?

@npmccallum
Copy link
Contributor

@mark-i-m I think we'd have to consider that on a feature-by-feature basis.

In your particular example, I don't think it is ever the intent to allow anything except asm blocks in a naked function. So, for example, we could relax the requirement to have a single asm block and the last asm block must have noreturn. But we can't ever let Rust do the return since returning in Rust almost always emits stack manipulation.

bstrie added a commit to bstrie/rust that referenced this issue Feb 2, 2022
This stabilizes the feature described in RFC 2972,
which supersedes the earlier RFC 1201.

Closes rust-lang#32408
Closes rust-lang#90957
@bstrie
Copy link
Contributor

bstrie commented Feb 2, 2022

I have submitted a stabilization proposal for the naked_functions feature in the tracking issue for RFC 2972: #90957 (comment) . I suggest that we continue further discussion in that thread. Since there has been some confusion regarding the relationship between RFC 1201 and RFC 2972, allow me to clarify: RFC 2972 supersedes RFC 1201 by defining a smaller legal subset of naked functions; it is essentially min_naked_functions (see also min_const_generics, min_specialization, etc.) but rather than using a new feature flag it has simply re-used the original naked_functions feature flag. The naked_functions feature as implemented in the compiler today conforms to RFC 2972, not RFC 1201. I propose that this tracking issue be closed, to reduce confusion and keep further discussion centralized.

@nikomatsakis
Copy link
Contributor Author

@rfcbot reviewed

I am in favor of NOT doing "extended naked functions" and just doing the constrained version.

@rfcbot rfcbot added final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. and removed proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. labels Feb 4, 2022
@rfcbot
Copy link

rfcbot commented Feb 4, 2022

🔔 This is now entering its final comment period, as per the review above. 🔔

@rfcbot rfcbot added finished-final-comment-period The final comment period is finished for this PR / Issue. to-announce Announce this issue on triage meeting and removed final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. labels Feb 14, 2022
@rfcbot
Copy link

rfcbot commented Feb 14, 2022

The final comment period, with a disposition to close, as per the review above, is now complete.

As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed.

@bstrie
Copy link
Contributor

bstrie commented Feb 15, 2022

I am not on the lang team, but since the FCP has ended I hope it is not presumptuous of me to close this in acknowledgement of the lang team's decision to supersede RFC 1201 with RFC 2972. Allow me to once again strongly encourage anyone interested in naked functions to please review the tentative stabilization report for RFC 2972's minimal subset of naked functions ( #90957 (comment) ); that stabilization is not yet in FCP, but it may become so relatively soon, so now is the time to bring up any concerns you may have.

@bstrie bstrie closed this as completed Feb 15, 2022
@apiraino apiraino removed the to-announce Announce this issue on triage meeting label Feb 17, 2022
bors added a commit to rust-lang-ci/rust that referenced this issue Dec 31, 2023
Update tracking issue of naked_functions

The original tracking issue rust-lang#32408 was superseded by the new one rust-lang#90957 (constrainted naked functions) and therefore is closed.
fmease added a commit to fmease/rust that referenced this issue Jan 2, 2024
Update tracking issue of naked_functions

The original tracking issue rust-lang#32408 was superseded by the new one rust-lang#90957 (constrainted naked functions) and therefore is closed.
fmease added a commit to fmease/rust that referenced this issue Jan 3, 2024
Update tracking issue of naked_functions

The original tracking issue rust-lang#32408 was superseded by the new one rust-lang#90957 (constrainted naked functions) and therefore is closed.
fmease added a commit to fmease/rust that referenced this issue Jan 3, 2024
Update tracking issue of naked_functions

The original tracking issue rust-lang#32408 was superseded by the new one rust-lang#90957 (constrainted naked functions) and therefore is closed.
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Jan 3, 2024
Rollup merge of rust-lang#119474 - nbdd0121:naked, r=Nilstrieb

Update tracking issue of naked_functions

The original tracking issue rust-lang#32408 was superseded by the new one rust-lang#90957 (constrainted naked functions) and therefore is closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-naked Area: `#[naked]`, prologue and epilogue-free, functions, https://git.io/vAzzS B-RFC-implemented Blocker: Approved by a merged RFC and implemented. B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. disposition-close This PR / issue is in PFCP or FCP with a disposition to close it. finished-final-comment-period The final comment period is finished for this PR / Issue. S-tracking-design-concerns Status: There are blocking ❌ design concerns. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.