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

Add support for naked functions. #1201

Merged
merged 3 commits into from Mar 21, 2016

Conversation

Projects
None yet
@tari
Copy link
Contributor

tari commented Jul 11, 2015

Rendered.

[edited to link to the final rendered version]

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Jul 11, 2015

👍 This would allow using only Rust + inline assembly in a kernel.
Definitely need to restrict this to either unsafe functions, or have unsafe in the name of the attribute (I prefer the former).

@nrc nrc added the T-lang label Jul 13, 2015

@DanielKeep

This comment has been minimized.

Copy link

DanielKeep commented Jul 14, 2015

How does this interact with the calling convention?

I recently looked into writing some inline assembly, using extern "C" so that I knew the layout of the stack, but it looks like in Rust this just creates an extern "C" landing pad that calls an extern "rust" function which is where the code actually lives.

If all this does is let us replace the contents of an extern "rust" function, and the Rust ABI is deliberately undefined, how is one supposed to write code that accesses arguments or returns anything?

I'm inclined to suggest that #[naked] be restricted not only to unsafe functions, but functions that use a "well-defined" ABI such as C or stdcall. Unless the Rust ABI is defined, there's no way #[naked] unsafe extern "rust" fn() { ... } can have any well-defined meaning.

@Tobba

This comment has been minimized.

Copy link

Tobba commented Jul 14, 2015

This doesn't seem like a terribly good idea, LLVM lacked this for a very long time due to the undefined and extremely iffy semantics involved, essentially the only thing that can safely be done in a naked function is using a single asm block. LLVM already has had support for module-level assembly blocks as long as I can remember.

Although I wouldn't let any remotely complicated hand-written code get within 50 feet of LLVMs built-in assembler either (it tends to be somewhat broken)

@tari

This comment has been minimized.

Copy link
Contributor

tari commented Jul 14, 2015

If all this does is let us replace the contents of an extern "rust" function, and the Rust ABI is deliberately undefined, how is one supposed to write code that accesses arguments or returns anything?

I think you're right that anything but parameterless functions returning () are difficult or impossible to write as naked. Interrupt handlers always match those criteria, but that seems like a good case in support of the extern "interrupt" alternative since doing anything else with a naked function is so sketchy.

LLVM already has had support for module-level assembly blocks as long as I can remember.

Without Rust support though, that doesn't get us very far. The advantage of putting this directly on functions is that we allow the compiler to generate a function definition, including name mangling.


Despite the much greater implementation complexity, I'm coming around to the extern "interrupt" option as more robust and safer than this one, especially if nobody can come up with a non-interrupt use case for naked functions.

@DanielKeep

This comment has been minimized.

Copy link

DanielKeep commented Jul 14, 2015

@tari: My point wasn't "you can't write naked functions that take arguments", it was "you can't write naked functions that take arguments using the undefined rust ABI". I've only written a few naked functions over the years, but every time I did, they had to be naked, and they had to take arguments. I think they were all trampolines of one kind or another.

I think the good solution is to make sure that naked functions aren't "desugared" into extern "rust" functions wrapped in an extern "$OTHER" trampoline. After all, I would only expect them to contain a single asm! directive, anyway, so the compiler shouldn't need to translate the ABI.

extern "interrupt", on the other hand, feels more like a "this is the only use case I care about" solution. :P

@Tobba

This comment has been minimized.

Copy link

Tobba commented Jul 14, 2015

extern "interrupt" gives the impression that the ABI is only for interrupt handlers, while that is not the case. How about extern "naked"?

Either way, the compiler could provide name mangling for module-level assembly blocks, which would be much saner.

@Diggsey

This comment has been minimized.

Copy link
Contributor

Diggsey commented Jul 14, 2015

Isn't name mangling seperate from the ABI already in rust, ie. extern "C" doesn't disable name mangling?

One problem with extern "interrupt"/extern "naked" is that it doesn't specify how the function should be called. For interrupts it's not a problem because you never call them directly, but there may be cases where you need to call a naked function directly from other rust code - in that case the compiler needs to know which ABI to use to call the function.

For this reason, I think it would be better to leave #[naked] as an attribute, but disallow its use in conjunction with extern "rust" functions.

Finally, there may be cases where the naked function doesn't follow any standard ABI, in which case it shouldn't be callable at all from rust code. This "unspecified" ABI could be selected via extern "unspecified", in which case the compiler would prevent it being called except via assembly.

@tari

This comment has been minimized.

Copy link
Contributor

tari commented Jul 14, 2015

I think the good solution is to make sure that naked functions aren't "desugared" into extern "rust" functions wrapped in an extern "$OTHER" trampoline. After all, I would only expect them to contain a single asm! directive, anyway, so the compiler shouldn't need to translate the ABI.

The trouble with that approach I see is that it becomes impossible to safely call such a naked function from Rust. We could choose to forbid native rust calls to such a function, but that seems to me like an unusual exception to the rule that all declared functions are callable.

extern "interrupt" gives the impression that the ABI is only for interrupt handlers, while that is not the case. How about extern "naked"?

Right; I started conflating the goal and means a bit here. Clarifying: my ultimate goal is to support writing interrupt handlers in Rust-only. The proposed means to that is introducing naked functions which allow the programmer to use an arbitrary calling convention.

As extern functions are implemented today, we cannot implement arbitrary ABI trampolines because the Rust ABI is unspecified and extern functions are implemented by the compiler as a trampoline to translate the calling convention to Rust and call the Rust-native version of a function. This is not a concern for interrupt handlers because they don't take any parameters, nor do they return any values.

Changing this approach would have the implication that some calls to functions defined in Rust become wrong because they assume a different calling convention- a hypothetical extern "naked" function implemented as a module-level assembly block would be unsafe to call from Rust because the ABIs will conflict and it is not possible for the compiler to generate a Rust-ABI version of the function.


Given the previous points, the simplest approach to supporting arbitrary ABIs appears to be implementing them in the compiler. This is much less flexible than supporting naked functions, but permits more efficient code generation since the compiler has detailed knowledge of what the system is doing. For the motivating use case this could be extern "interrupt" to use a target-specific interrupt ABI, or something like extern "fortran" for Fortran FFI.

Addition of calling conventions doesn't preclude a generic mechanism for naked functions, but it does sidestep the current issues involved in making naked functions useful.

@DanielKeep

This comment has been minimized.

Copy link

DanielKeep commented Jul 14, 2015

The trouble with that approach I see is that it becomes impossible to safely call such a naked function from Rust. We could choose to forbid native rust calls to such a function, but that seems to me like an unusual exception to the rule that all declared functions are callable.

A naked function is no less safe to call than any other non-local extern "C" function. Heck, that C ABI function you're linking to might very well be implemented in pure assembly for all you know!

I get the feeling that we're starting to talk across purposes, here, so let's clarify. I'm talking about something like:

#[cfg(target_arch="x86")]
extern "C" fn add_two(a: i32, b: i32) -> i32 {
    #![naked]
    asm!(r#"
        mov eax, [esp+4]
        mov ecx, [esp+8]
        add eax, ecx
    "#)
}

fn main() {
    assert_eq!(add_two(4, 6), 10);
}

Unless I've got the assembler wrong (it's been a while), the above should be perfectly safe to call. It's a function that uses the C ABI... that it's written in assembler and doesn't have the standard function prelude is just an implementation detail the user doesn't need to worry about.

I mean, rustc has to be able to call extern "C" functions; it's just that the code it generates when it's defining them is a bit unexpected.

@tari

This comment has been minimized.

Copy link
Contributor

tari commented Jul 14, 2015

A naked function is no less safe to call than any other non-local extern "C" function. Heck, that C ABI function you're linking to might very well be implemented in pure assembly for all you know!

The difference is that the only reason to use a naked function is when the compiler does not understand the ABI you need to use and is thus virtually guaranteed to generate code that will do something unexpected (and wrong) if you try to call it. You can implement a naked function that uses the C ABI, but there's no reason to do so because the compiler already understands how to deal with that for you.

@Diggsey

This comment has been minimized.

Copy link
Contributor

Diggsey commented Jul 14, 2015

@tari That's simply not true - there are many reasons to require a naked function even when using an ABI that the compiler understands.

@tari

This comment has been minimized.

Copy link
Contributor

tari commented Jul 14, 2015

Can you provide some examples of situations you'd want to do so? The way I see it, naked functions are useful to fill holes in the compiler's ABI support and I don't see the point of using one when the compiler is capable of doing what you need.

@Diggsey

This comment has been minimized.

Copy link
Contributor

Diggsey commented Jul 14, 2015

Sometimes you can implement a method more efficiently than the compiler's default prolog/epilog would allow. For example, I needed to write a function which returned the address of the caller. With a naked function, this boils down to two instructions:

mov eax, [ebp+4]
ret

There's just no way to generate code like that without getting rid of the default prolog and epilog.

@main--

This comment has been minimized.

Copy link

main-- commented Jul 14, 2015

@Diggsey While specific stack layout (e.g. caller address being at [ebp+4]) is undefined in the rust ABI, prolog/epilog optimization is generally the compiler's job. So if we just ignore the fact that the result of this function is essentially undefined, you can do this:

#![feature(asm)]

pub fn myfunc() -> u32 {
    let ret: u32;
    unsafe { asm!("mov $0, [ebp+4]" : "=r"(ret) ::: "intel"); }
    return ret;
}
// yes, I'm compiling this on x86_64, so it won't ever work like this anyways but it really doesn't matter for this example
$ rustc -O --crate-type rlib test.rs
$ objdump -CdMintel libtest.rlib 
Disassembly of section .text._ZN6myfunc20h9064a5bb1ed9f519eaaE:

0000000000000000 <myfunc::h9064a5bb1ed9f519eaa>:
   0:   67 8b 45 04             mov    eax,DWORD PTR [ebp+0x4]
   4:   c3                      ret    

And there you go. Exactly what you wanted, without a naked function.

@tari

This comment has been minimized.

Copy link
Contributor

tari commented Jul 14, 2015

It seems we have two somewhat distinct use cases for naked functions, where I only had the first in mind while writing this RFC:

  • Papering over holes in the compiler's ABI support (allowing a user to handle the ABI themselves).
  • Implementing optimized or machine-specific functions.

Neither of these works well with the current proposal, because the ABI of function calls generated by the compiler is unspecified. For a compiler-generated call to such a function, we should require that the ABI in use be well-defined (specifically it must not use the Rust ABI, and we may want to restrict it to extern "C" only). This matches the semantics of naked functions in C, where the ABI of a given function is always known from source code and platform alone, and is usually (but not always) the default calling convention.

If the calling convention of a naked function which is called from Rust code is constrained to be well-defined, the problems are purely in implementation- rustc must learn how to use non-Rust calling conventions for functions it defines (rather than ones it merely links against).


@main-- that may be technically possible, but it's too fragile for me to be comfortable encouraging such a thing. We can make the static guarantees of such a function stronger by allowing it to be declared as naked without affecting the rest of the language, so I believe we should.

@main--

This comment has been minimized.

Copy link

main-- commented Jul 14, 2015

I agree that especially for things like interrupt handlers, naked functions are simply a necessity. Of course one could try and hack around that by calling into an embedded inline asm block, but that's far from perfect.

I do have doubts regarding ABI emulation (providing functions in a specific ABI without compiler support): Every function needs its own trampoline, right? So one would probably write a macro to create all those trampolines which ... surprisingly isn't even that messy, but still less pretty than it could be (extern "fancyabi").

When calling a method, we need to know how. In case of a "standard" naked function, this gets us into a funny situation: Just like with any normal function, we're supposed to use the Rust ABI which is fine for us - but at the same time we're sure that they (callee) can never handle this correctly due to that ABI being undefined. I'd suggest making those functions uncallable and forcing them to be parameterless.

On the other hand, when a naked function's ABI has a well-known definition (like extern "C"), all is well; no need to impose any further restrictions.

The other difficult part are local variables. Should you write "heavy" rust code within naked functions? Probably not. But it should definitely be possible within certain limits. Why else would you use Rust if you could just write your function in plain asm (much better tooling than inline asm)? Straight up banning locals is not a great solution, but since the compiler can't really reserve stack space either (naked --> no prolog) something like MSVC's __LOCAL_SIZE is probably inevitable. The really ugly part about that particular approach is that the compiler is forced to emit even useless prologs and epilogs (when no stack spilling is required). So one can either sacrifice performance by having them or sacrifice non-optimized builds altogether since rustc (like many compilers) likes to just hold everything on the stack and then rely heavily on the optimizer to eliminate these useless stack operations, simply resulting in broken code without that.

@aidancully

This comment has been minimized.

Copy link

aidancully commented Jul 16, 2015

Sorry for this, but... is this a problem that needs solving? I do a lot of systems programming, and do my best to avoid inline assembly where I can. Usually, what I'll do instead (especially for something like an interrupt handler), is write an assembly file and have it call out to a C-ABI routine to get a trampoline to more maintainable code. I don't yet see how #[naked] is technically superior to just writing assembly when you want to use assembly, and then interacting through an FFI?

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Jul 16, 2015

@aidancully arbitrary codegen driven by Rust code, basically.
I don't know why this is not mentioned, but being able to output naked functions from macros and even monomorphization is quite useful:

static HANDLERS: [AtomicPtr<()>; 256] = [AtomicPtr::new(); 256];
#[naked]
unsafe fn handle_interrupt<F: Fn()>(number: u8) {
    (*(HANDLERS[number as usize].load(Relaxed) as *const F))();
    asm!("iret");
}
@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Jul 16, 2015

Are there links to LLVM discussion on this topic?

@tari

This comment has been minimized.

Copy link
Contributor

tari commented Jul 16, 2015

I haven't found any meaningful LLVM discussion on it. Support was added in 2009, r76198, which may be a good starting point for searching.

Constrain calling of naked functions from Rust
Also expand motivation beyond ISRs per RFC discussion.
@Tobba

This comment has been minimized.

Copy link

Tobba commented Jul 16, 2015

@eddyb That code is most certainly broken. If the compiler ever spills a register, you're fucked. Since it's also an interrupt handler, it should avoid clobbering registers, which is impossible to do efficiently in any way that will please LLVM.

In general the only way you're ever going to get the correct output is by having a single asm block within the function, which is just a hacky version of module-level assembly.

@main--

This comment has been minimized.

Copy link

main-- commented Jul 17, 2015

If the compiler ever spills a register, you're fucked.

While the RFC currently doesn't address this issue it's not a problem with naked functions in general as solving it is possible (and probably necessary; see my previous comment).

@aidancully

This comment has been minimized.

Copy link

aidancully commented Jul 18, 2015

@eddyb For what it's worth, I find that type of use plausible as a motivator, but I also worry that it might be very challenging to make #[naked] functions work in a generic fashion. And in that specific case, I don't think I'd write that function in a generic way: why should I need to monomorphize a function that just dereferences a function pointer and calls it? The code that will be generated during monomorphization will likely be identical, I don't want multiple copies! And, I want to make sure that the way I call the function will be valid, which can be hard to do without knowing the ABI of the called routine... But if I need to know the ABI, do I possibly require a prologue or epilogue for some types of function call? Maybe there's a solution that allows us to use the ABI as a parameter? Maybe something like this:

static HANDLERS: [AtomicPtr<()>; 256] = [AtomicPtr::new(); 256];
#[naked]
unsafe fn handle_interrupt<F: Fn()>(number: u8)
{
    // F::ABI's static functions are #[naked] #[inline].
    F::ABI::create_calling_env();
    (*(HANDLERS[number as usize].load(Relaxed) as *const F))();
    F::ABI::destroy_calling_env();
    asm!("iret");
}

But if this sort of thing is necessary to safely support generic naked functions, it'd probably need to be reflected in the RFC. (Note that I don't think the whole change would need to land at once, the initial patch sounds pretty small and may be acceptable in the short term. But the design space in which the feature would be used probably needs to be explored better... I think there's a significant risk that, even though #[naked] functions themselves are pretty simple, making them useful in a Rust context might get pretty complicated.)

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Jul 18, 2015

@aidancully if you don't generate multiple monomorphizations, you need to use indirect calls, which might be a measurable cost during interrupt handling - but it is a micro-optimization and I could very well be wrong about it.

@tari

This comment has been minimized.

Copy link
Contributor

tari commented Jul 18, 2015

If I understand the current tack of the discussion now, the main concern is that the effect of writing code that is not inline assembly in a naked function is unpredictable. The correctness of the handle_interrupt example depends entirely on what codegen yields as currently proposed. Some users might be willing to accept the risk of doing so in the name of small gains, but doing so is fundamentally unsafe. This is the logic behind the current requirement that the body of a naked function contain only unsafe statements- inline assembly already requires unsafe, and the result of anything else cannot be guaranteed by the compiler.

A way to ask the compiler how much space it needs for locals would permit a solution, but there's no mechanism to enable that in LLVM. I see a way forward in having an LLVM intrinsic function that is guaranteed to lower to a constant load representing the necessary size of locals, but I think such a significant change is beyond the scope of this proposal.

With the __LOCAL_SIZE-like solution off the table, the only way to enforce (relative) safety is if only assembly is permitted in naked functions. This approach gives the compiler freedom to implement such a thing as either a module-level assembly block (with name mangling) or a true naked function, while permitting future extensions to relax the requirements (with a __LOCAL_SIZE workalike for example). On the downside, users willing to accept a certain amount of undefined behavior (trusting the compiler's behavior will be stable enough to make use of) can't choose to make that tradeoff anymore.

@tari

This comment has been minimized.

Copy link
Contributor

tari commented Jul 18, 2015

On the downside, users willing to accept a certain amount of undefined behavior (trusting the compiler's behavior will be stable enough to make use of) can't choose to make that tradeoff anymore.

Both cases could be accommodated by putting support for Rust statements in naked functions behind a feature gate; something like error: Rust statements in naked functions are extremely unsafe and may require additional guarantees in the future. This permits the statically-safe version (assuming the programmer doesn't write bugs) with inline assembly only, while allowing adventurous users to be extremely unsafe until a better solution can be chosen.

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Jul 31, 2015

In a recent lang subteam meeting, we decided to close this PR. This RFC seems to have a lot in common with #55, which was closed by @brson with the following rationale:

So far we've resisted exposing platform-specific linkage options, besides the limited ability to declare weak extern statics. If we were to pursue that I think I would want a more comprehensive proposal.

Naked functions clearly have some use but there is a workaround of just writing it in assembly.

The situation seems not to have changed very much -- basically it seems a bit premature to be introducing these sorts of constructs. The concerns about running Rust code in naked functions seem particularly salient.

(Taking off my lang subteam hat for a moment and speaking personally, I think I would prefer to address this by writing naked functions in pure assembly and linking them in with LTO -- or having a variant on inline assembly that generates an entire function.)

@aturon aturon removed the I-nominated label Mar 17, 2016

@vitiral

This comment has been minimized.

Copy link

vitiral commented Mar 18, 2016

I've only worked with interrupts in microcontrollers, but why can't you have the interrupt just use the existing stack? It is the nature of interrupts that they have to return before anything else can run. (this is how it works on a microcontroller)

@Amanieu

This comment has been minimized.

Copy link
Contributor

Amanieu commented Mar 18, 2016

I've added an RFC (#1548) for module-level inline assembly. I think this feature can replace the need for naked functions in many cases.

@thepowersgang

This comment has been minimized.

Copy link
Contributor

thepowersgang commented Mar 18, 2016

@Amanieu - That sounds like a much better idea.

I've been pretty hesitant on naked functions, because they're either unknown magic, or exceptionally limited.

All you get over module-level inline assembly is free naming and symbol size (assuming the pure-bare version of naked functions).

@arcnmx

This comment has been minimized.

Copy link

arcnmx commented Mar 18, 2016

All you get over module-level inline assembly is free naming and symbol size (assuming the pure-bare version of naked functions).

As I touched on in #1201 (comment), I personally feel like this is actually the main advantage of the RFC. You should be able to simulate both module-level asm and asm-only naked functions with a macro, so mostly I see this as an ergonomics discussion. Using rust code in naked functions is something I'm not really missing and don't have as much of an opinion on, but maybe following the llvm/clang/gcc semantics is good enough...

I'd also support module-level inline assembly, as it's a rather useful feature, though if you can't use symbols/constants/etc. that's a pretty unfortunate limitation... Both module-level asm and naked functions are just plain things that should exist in Rust IMO. All too often the lower level aspects get neglected despite being branded as a systems language...

@ketsuban

This comment has been minimized.

Copy link

ketsuban commented Mar 18, 2016

I have to admit the comments on this RFC have kind of lost me. Perhaps this just needs the ELI5 treatment.

I started off following the interrupt calling convention RFC and followed the pointer here; I got the impression there were other unrelated problems and naked functions are a more general solution to both domains.

Now I'm here, this RFC is in FCP and I still don't really understand why naked functions which can only contain a single block of inline assembly are useful. That's enough to call a proper function, sure, but at that point I might as well just make a small assembly file—I already have a larger assembly file which does the necessary prep work to start running Rust code in the first place, so it's not like I can avoid invoking an assembler at all.

By comparison with the Visual C++ example on the OSdev wiki (the only listed compiler which uses naked functions rather than a special interrupt function annotation to indicate the compiler should emit a prologue/epilogue specific to an interrupt handler) this is what I see a Rust interrupt handler built out of a naked function looking like.

naked fn interrupt_handler() {
    asm!("push rax");
    asm!("push rcx");
    // push everything ...
    // Rust code to service the interrupt goes here
    // pop everything ...
    asm!("pop rcx");
    asm!("pop rax");
    asm!("iret");
}

Am I mistaken?

@arcnmx

This comment has been minimized.

Copy link

arcnmx commented Mar 18, 2016

I already have a larger assembly file which does the necessary prep work to start running Rust code in the first place, so it's not like I can avoid invoking an assembler at all.

Note that this isn't really true in all cases, so there's value in being able to avoid bringing in an external assembler entirely! I have an armv7m kernel that only uses asm for interrupt handler trampolines, all inline, and the entry point is pure rust, for example.

@ticki

This comment has been minimized.

Copy link
Contributor

ticki commented Mar 18, 2016

Perhaps this just needs the ELI5 treatment.

The proposed #[naked] attribute indicates that the specified function does not need prologue/epilogue sequences generated in the compilation process. It is up to the programmer to provide these sequences.

In basic terms, this makes rustc capable of doing all the low-level stuff which C is able to. Such as:

  • Possibility of implementations of green threading.
  • Interrupt handling.
  • Context switching.

All in Rust, without needing external files.


This is especially important when dealing with low-level stuff, such as OS development.

We for example need this in Redox (an OS written in pure Rust) to get x86 support working. So this is really an important feature to us.


An example for the curious would be a custom interrupt handler function:

#[cfg(target_arch = "x86")]
fn interrupt_handler() {
    asm!("iretd");
}

This function will currently generate code as:

interrupt_handler:
  push ebp
  mov ebp, esp
  iretd
  ret

(truncated for simplicity)

With the #[naked] attribute (which is implemented with PR #29189), it will bypass the prologue and epilogue sequences. And the output will be like:

interrupt_handler:
  iretd

Namely, it is a way of bypassing the automatically generated sequences, which pop/push to the stack.

@rustonaut

This comment has been minimized.

Copy link

rustonaut commented Mar 21, 2016

Given that rust is meant to be a system level programming language, I think it is needed to have this feature (or a similar on) in rust.

Through it is needed for low level tasks for many people given that this feature is not needed or even bad style in less low level code I would propose that (if available in stable) there is per default lint like #[deny(naket_fn)] or similar (or it just stays featur-gated forever, would probably be fine too?).

Also even through module level asm seems to* be able to emulate naked fn's I think naked fn's are much clearer for use cases like interrupts.

(* I might have missed something, but naked fn's can contains (some) "normal" rust code, but module level asm can't, or?)

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Mar 21, 2016

@Naicode Naked functions have to be assembly-only.
However, platform-specific interrupt ABIs would be much more useful for interrupt handlers, as you could have Rust code inside them and not care about, e.g. needing iret to return.

@rustonaut

This comment has been minimized.

Copy link

rustonaut commented Mar 21, 2016

Ok, so module level asm and naked functions most likely can emulate each other.

Hm, I't might be able to implement platform-specific interrupt handling by combining macros with naked functions, leaving naked functions still there for the other use cases.
(through not implementing them as simple rust macros might enable a higher degree of validity checking, my interrupt related knowledge is a bit limited, so I can't judge if it is possible)

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Mar 21, 2016

@Naicode You would want to implement the whole Rust language in macros?

@rustonaut

This comment has been minimized.

Copy link

rustonaut commented Mar 21, 2016

@eddyb No! that would be horribly ;=)

What I meant, is that, if the naked fn's can only contain asm, you would either write the complete ISR in assembly or delegate to a rust-fn at some point. This boiler part could be be written as a macro...

e.g. the example from the rfc:

#[naked]
#[cfg(target_arch="x86")]
unsafe fn isr_3() {
    asm!("pushad
          call increment_breakpoint_count
          popad
          iretd" :::: "volatile");
    intrinsics::unreachable();
}

could be written like:

delegate_isr_3!(increment_breakpoint_count)

Through in the end having a rust native ISR ABI might be more performant/useful

Also you could pass a codeblock to a macro, but it probably wouldn't be a good idea to use it without wrapping it in a function because it might contain a return statement (and possible other "bad" thinks), but you could also have a way to forbid return statements in code block passed to macro, well that is a different topic.

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Mar 21, 2016

Huzzah! The @rust-lang/lang team has decided to accept this RFC. As previously stated, this is being accepted on a particularly experimental basis, especially with respect to the semantics (or lack thereof) of Rust code embedded in a naked function. One plausible route for stability would be to stabilize the #[naked] attribute when the function contains only assembler, or meets other similar criteria -- but without having some experience with the attribute, we'll never know what those criteria ought to be.

@nikomatsakis nikomatsakis merged commit 1cc857f into rust-lang:master Mar 21, 2016

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Mar 21, 2016

Tracking issue rust-lang/rust#32408.

@ticki

This comment has been minimized.

Copy link
Contributor

ticki commented Mar 21, 2016

Thanks, thanks, thanks, @rust-lang/lang.

@ticki

This comment has been minimized.

Copy link
Contributor

ticki commented Mar 21, 2016

PR submitted: rust-lang/rust#32410

bors added a commit to rust-lang/rust that referenced this pull request Mar 23, 2016

Auto merge of #32410 - Ticki:master, r=eddyb
Add support for naked functions

See rust-lang/rfcs#1201 (comment)

This PR adds `#[naked]` for marking naked functions.

@tari tari referenced this pull request May 23, 2016

Merged

Correct example in 1201 #1627

@hawkw hawkw referenced this pull request Jun 1, 2016

Closed

towards "boot.rs" #17

4 of 4 tasks complete
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment