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

RFC 1201 amendments: Naked function corrections #2774

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 14 additions & 22 deletions text/1201-naked-fns.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,15 @@ address of its caller when called with the C ABI on x86.
---

Because the compiler depends on a function prologue and epilogue to maintain
storage for local variable bindings, it is generally unsafe to write anything
but inline assembly inside a naked function. The [LLVM language
reference](http://llvm.org/docs/LangRef.html#function-attributes) describes this
feature as having "very system-specific consequences", which the programmer must
be aware of.
storage for local variable bindings, including anything but inline assembly
inside a naked function is not allowed. Refering to the parameters inside of a
Copy link
Member

Choose a reason for hiding this comment

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

This seems to suggest that you can have a naked function with parameters, but you can't use them. This seems incorrect - parameters will always have an implicit use due to the generated drop calls. Shouldn't naked functions be forbidden from taking any parameters?

Copy link
Author

Choose a reason for hiding this comment

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

That was my original intention, but passing arguments still makes sense as you can reference them directly from the registers in the assembly.

Copy link
Member

Choose a reason for hiding this comment

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

That would require rust to generate a prologue, though - which naked functions are supposed to avoid.

Copy link

Choose a reason for hiding this comment

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

No, it doesn't require rust to generate a prologue, it requires the ASM author to know about the calling convention (which is the case for extern C functions) and properly handle it themselves.

drop calls are a good point. I guess arguments should be !Drop?

Copy link
Member

Choose a reason for hiding this comment

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

@roblabla: What if the calling convention requires generating a prologue? I don't think a naked fn should cause Rust to generate some weird subset of the normal ASM for a function.

Note that it's not sufficient to require arguments to be !Drop - they also must not have any drop glue (e.g. struct MyStruct(String) is !Drop but has drop glue).

I really don't see passing parameters to naked functions as being useful, or even very well-defined.

Copy link

@roblabla roblabla Oct 8, 2019

Choose a reason for hiding this comment

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

Then they should be Copy - which AFAIU denies the drop glue. This is similar to the restrictions union currently have - unions may not have items that are Drop, so as an approximation they only allow Copy types.

Passing parameters to naked function that have a known ABI (such as extern "C") is well-defined - that's sort of the whole point of those ABIs. If a CC requires a prologue as part of the ABI, then it's up to the person writing the naked function to insert that prologue. This is similar to defining functions with global_asm!.

People have further shown that they are useful - for instance look at this comment.

naked function is also not allowed.

# Detailed design

Add a new function attribute to the language, `#[naked]`, indicating the
function should have prologue/epilogue emission disabled.
function should have prologue/epilogue emission disabled. Naked functions
will never be inlined.

Because the calling convention of a naked function is not guaranteed to match
any calling convention the compiler is compatible with, calls to naked functions
Expand Down Expand Up @@ -116,19 +115,22 @@ the functions `correct1` and `correct2` are permitted.

```
#[naked]
extern "C" fn error(x: &mut u8) {
*x += 1;
#[cfg(target_arch="x86")]
extern "C" fn error() {
unsafe { asm!("int3") }
}

#[naked]
unsafe extern "C" fn correct1(x: &mut u8) {
*x += 1;
#[cfg(target_arch="x86")]
unsafe extern "C" fn correct1() {
unsafe { asm!("int3") }
}

#[naked]
extern "C" fn correct2(x: &mut u8) {
#[cfg(target_arch="x86")]
extern "C" fn correct2() {
unsafe {
*x += 1;
unsafe { asm!("int3") }
}
}
```
Expand Down Expand Up @@ -197,16 +199,6 @@ external libraries such as `libffi`.

# Unresolved questions

It is easy to quietly generate wrong code in naked functions, such as by causing
the compiler to allocate stack space for temporaries where none were
anticipated. There is currently no restriction on writing Rust statements inside
a naked function, while most compilers supporting similar features either
require or strongly recommend that authors write only inline assembly inside
naked functions to ensure no code is generated that assumes a particular stack
layout. It may be desirable to place further restrictions on what statements are
permitted in the body of a naked function, such as permitting only `asm!`
statements.

The `unsafe` requirement on naked functions may not be desirable in all cases.
However, relaxing that requirement in the future would not be a breaking change.

Expand Down