-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Conversation
My personal preference is for option 2, but only for for extern "C" functions. Calling naked functions with arguments from other Rust code otherwise becomes much harder. I'm not actually sure how it could work. Combining the naked function definition with a separate extern declaration containing the real argument list seems hypothetically possible but doesn't really seem like an improvement? If we're tweaking the rules for naked functions, we should probably also say that the compiler is no longer allowed to inline them. |
Is is possible to pass that information down to LLVM to have it handle that?
Yes, this will be difficult to do, but from my understanding of the current RFC that is discouraged anyway.
Yeah, I guess that is possible.
Good idea, I'll add an extra commit to this PR with that. |
I have added a change about inlining naked functions |
Naked functions with arguments are useful. For instance, to do a system call: #[naked]
pub unsafe fn stat(buf: *const u8, buf: *const u8) {
asm!("mov $0x20000bc, %%eax; syscall");
} I don't see a reason to ban them. At most, rustc could emit a warning until the LLVM bug has been confirmed fixed. |
LLVM specifically specifies:
https://reviews.llvm.org/D5183 so although it seems useful I don't think it should be supported. |
I am open to a warning though, which would allow people who really want to have arguments use them but discourage people from doing it. Also, while we are changing everything should we fix the unresolved question of allowing non |
I have updated the PR to indicate that naked functions will never be inlined as the LLVM code won't inline a naked function. This makes that information explicit. https://github.com/llvm/llvm-project/blob/master/clang/lib/CodeGen/CodeGenModule.cpp#L1539 |
The current compiler is definitely willing to inline a naked function: https://rust.godbolt.org/z/n9JvSL #![feature(naked_functions)]
#![feature(asm)]
#[naked]
extern "C" fn foo() {
unsafe { asm!("int3") }
}
pub fn main() {
foo();
} Produces this assembly: example::main:
int3
ret |
You don't refer to the parameters explicitly (i.e. naming then in constraints). Instead, the assembly code in the inline asm block would expect them to be in certain registers as per the platform ABI. Normally you wouldn't be allowed to assume anything about register state from an inline asm block, but the point of naked functions is that the contents of the block make up the entire body of the function; the compiler won't do any register manipulation behind your back. Or at least, it's not supposed to. |
The code you linked is from Clang, not LLVM proper. It sounds like rustc should be doing the same thing (adding the Edit: Which corresponds to the bug report that @fintelia linked. |
Ok, I'm going to drop the arguments change and do some more research. It sounds like arguments should be supported and there is a bug somewhere in the naked function handling, either in rust or LLVM. On the other hand function arguments shouldn't be directly accessed and I think naked functions should never be inlined. I'll update the patches with those changes. |
If naked functions should only have a single asm statement, and shouldn't be inlined, what's the difference between them and global_asm? It seems to me that they could be desuggared simply: // Original:
#[naked]
pub unsafe fn stat(buf: *const u8, buf: *const u8) {
asm!("mov $0x20000bc, %%eax; syscall");
}
// Desuggared:
global_asm! {
"""
.global mangled_stat
mangled_stat:
mov $0x20000bc, %%eax; syscall
"""
}
extern {
#[link_name = "mangled_stat"]
fn stat(buf: *const u8, buf: *const u8);
} This would sidestep the asm bug, and further enforce the rule that Naked functions must only contain a single asm call. |
There's not much difference. Indeed, naked functions may not be truly necessary to have as a feature, but some people apparently prefer them over
|
I think that @roblabla's example shows a couple more reasons why people prefer naked functions:
|
I have updated the PR to drop the argument removal requirement and to add some new ones. Let me know what you think. |
Thoughts on the new commits? |
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 |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
Any update on this? |
Typos in the commit messages and PR title: "ammendments" -> "amendments" |
clang will automatically set the NoInline attribute for naked functions and the NoInline attribute wins over AlwaysInline attribute. Let's follow their lead and specify the same requiremet. As the compiller can't safely change/remove the prologue and epilogue for naked functions when it inlines them inlining the naked functions could result in strange bugs. Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Following the requirements of clang/LLVM let's do two things: - Require naked functions to only contain inline assembly - Require naked functions to not reference the parameters As the compiler doesn't make any guarentees about the stack the two above points would be unsafe to allow. Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
I have fixed the typos and rebased on master. Any other thoughts? |
Just to summerise where we are:
|
Validate naked functions definitions Validate that naked functions are defined in terms of a single inline assembly block that uses only `const` and `sym` operands and has `noreturn` option. Implemented as future incompatibility lint with intention to migrate it into hard error. When it becomes a hard error it will ensure that naked functions are either unsafe or contain an unsafe block around the inline assembly. It will guarantee that naked functions do not reference functions parameters (obsoleting part of existing checks from rust-lang#79411). It will limit the definitions of naked functions to what can be reliably supported. It will also reject naked functions implemented using legacy LLVM style assembly since it cannot satisfy those conditions. rust-lang/rfcs#2774 rust-lang/rfcs#2972
Closing as this isn't being merged. |
Reject all uses of the inline attribute on naked functions. rust-lang/rfcs#2774 rust-lang/rfcs#2972
Validate that naked functions are never inlined Reject all uses of the inline attribute on naked functions. rust-lang/rfcs#2774 rust-lang/rfcs#2972 cc `@joshtriplett` `@tmiasko` `@Amanieu`
Test that FFI-safety warnings don't get accidentally dropped on naked functions. The big picture is that if you implement a naked function with the Rust ABI you'll get a warning. Further, if you implement a naked function with a standardized ABI, but use non-FFI-safe types you will still get a warning. rust-lang/rfcs#2774 rust-lang/rfcs#2972
This check was previously categorized under the lint named `UNSUPPORTED_NAKED_FUNCTIONS`. That lint is future incompatible and will be turned into an error in a future release. However, as defined in the Constrained Naked Functions RFC, this check should only be a warning. This is because it is possible for a naked function to be implemented in such a way that it does not break even the undefined ABI. For example, a `jmp` to a `const`. Therefore, this patch defines a new lint named `UNDEFINED_NAKED_FUNCTION_ABI` which contains just this single check. Unlike `UNSUPPORTED_NAKED_FUNCTIONS`, `UNDEFINED_NAKED_FUNCTION_ABI` will not be converted to an error in the future. rust-lang/rfcs#2774 rust-lang/rfcs#2972
In most calling conventions, accessing function parameters may require stack access. However, naked functions have no assembly prelude to set up stack access. This is why naked functions may only contain a single `asm!()` block. All parameter access is done inside the `asm!()` block, so we cannot validate the liveness of the input parameters. Therefore, we should disable the lint for naked functions. rust-lang/rfcs#2774 rust-lang/rfcs#2972
Disable unused variable lint for naked functions In most calling conventions, accessing function parameters may require stack access. However, naked functions have no assembly prelude to set up stack access. This is why naked functions may only contain a single `asm!()` block. All parameter access is done inside the `asm!()` block, so we cannot validate the liveness of the input parameters. Therefore, we should disable the lint for naked functions. rust-lang/rfcs#2774 rust-lang/rfcs#2972 `@joshtriplett` `@Amanieu` `@haraldh`
Validate FFI-safety warnings on naked functions Test that FFI-safety warnings don't get accidentally dropped on naked functions. The big picture is that if you implement a naked function with the Rust ABI you'll get a warning. Further, if you implement a naked function with a standardized ABI, but use non-FFI-safe types you will still get a warning. rust-lang/rfcs#2774 rust-lang/rfcs#2972 cc `````@joshtriplett````` `````@Amanieu````` `````@haraldh`````
Validate FFI-safety warnings on naked functions Test that FFI-safety warnings don't get accidentally dropped on naked functions. The big picture is that if you implement a naked function with the Rust ABI you'll get a warning. Further, if you implement a naked function with a standardized ABI, but use non-FFI-safe types you will still get a warning. rust-lang/rfcs#2774 rust-lang/rfcs#2972 cc ``````@joshtriplett`````` ``````@Amanieu`````` ``````@haraldh``````
Move naked function ABI check to its own lint This check was previously categorized under the lint named `UNSUPPORTED_NAKED_FUNCTIONS`. That lint is future incompatible and will be turned into an error in a future release. However, as defined in the Constrained Naked Functions RFC, this check should only be a warning. This is because it is possible for a naked function to be implemented in such a way that it does not break even the undefined ABI. For example, a `jmp` to a `const`. Therefore, this patch defines a new lint named `UNDEFINED_NAKED_FUNCTION_ABI` which contains just this single check. Unlike `UNSUPPORTED_NAKED_FUNCTIONS`, `UNDEFINED_NAKED_FUNCTION_ABI` will not be converted to an error in the future. rust-lang/rfcs#2774 rust-lang/rfcs#2972
This PR does two things both related to naked functions. Check the individual commits for more details.