-
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
Add global_asm! for module-level inline assembly #1548
Conversation
In my limited knowledge module-level assembly in LLVM is not very well supported. |
I've used it in Clang before and it worked fine for me. It was added to LLVM relatively recently however, so there may have been bugs in older versions. |
I've been a fan of module level assembly over naked functions for a while. It would be nice however if LLVM supported extended module level assembly, i.e. that with constraints. Symbol and constant constraints do make sense at least. |
As the naked functions RFC was just accepted, is this still necessary? |
It's still useful as a way of including external assembly files. |
|
Module-level inline assembly can also be useful for miscellaneous things other than functions, e.g. |
Is there a particular reason this needs to be a separate macro? i.e. can we just use |
|
@Amanieu that seems like a perfectly reasonable restriction ( |
@huonw That is fine too I guess. I decided to use a separate name because module-level assembly is quite different from function-level assembly. |
As I said above, some sort of constraints do make sense for top-level assembly. Therefore, I like using |
Nominating for discussion at lang meeting. I'm in favour of this RFC in the abstract. I guess the big question is whether, given we've accepted naked functions, whether we want this facility as well. |
|
||
There are two main use cases for this feature. The first is that it allows functions to be written completely in assembly, which mostly eliminates the need for a `naked` attribute. This is mainly useful for function that use a custom calling convention, such as interrupt handlers. | ||
|
||
Another important use case is that it allows external assembly files to be used in a Rust module without needing hacks in the build system: |
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.
Could you detail what exact build system hacks are required currently to support external asm files?
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.
You need an external assembler. Where is it? Is it the right version? Does it support the target platform(s)? Does it output in the proper location? etc etc. All this makes for ugly build.rs
boilerplate, and worse incremental rebuilds.
This aspect of the motivation is exactly the same as that for naked functions.
There is actually a rather significant downside, which I've only noticed recently: you don't get any line debug information with |
@Amanieu, not that it wouldn't be a lot of work, but I suspect that |
My personal opinion that all that we really need to do here is create an assembly counterpart of llvm_build_utils crate. Not only it would support having proper debuginfo, you wouldn’t be restricted to the weird LLVM favour of assembly which supports no features assembly programmers would expect for any larger stride of assembly (macros?) Is there really any use for having a big chunk of assembly code defining functions inline with rust code? |
🔔 This RFC is now entering its final comment period 🔔 |
I would rather have module level assembly use the I would really like us to completely redo our |
I haven't seen much discussion about the comparison between this and naked functions. Personally, I'm not opposed to module-level assembly -- and definitely prefer it to naked functions in some respects, for example it's (relatively) clear semantics -- but it seems like being able to replace naked functions is a pretty serious motivator. cc @jackpot51 and @tari for their thoughts here. I agree with @ubsan that it'd probably be nicer to use the same Do we need to provide any particular guarantees as to where in the generated assembly this section appears? In general it feels like, while the semantics are fairly clear, this RFC does leave a fair number of unknowns (it's pretty short, for one thing). Considering all this, I think overall I am currently inclined to close and maybe revisit later when we have gained more experience with naked fns. |
I personally think adding naked functions was a bad idea, so I proposed this RFC as an alternative. I just feel that naked functions are too hard to use correctly since the only way to use them is if the entire contents of the function is just a single Regarding the syntax, I chose a different name since Allowing |
That sounds like a LLVM limitation (which would need some rustc support), rather than an inherent problem with this approach. Definitely fixable, but I don't know enough about how LLVM handles debug info to say what it might take.
I think this is a useful point in favor of making the syntax be With the interpretation of this feature as filling a hole in current Comparing the approaches, an item referred to by Rust code requires less boilerplate when implemented as a naked function (no
There's definitely room for improvement with that. The MSVC support for custom prolog/epilog (with non-asm code in the body) came up in the naked RFC discussion, which could be ported in some fashion to LLVM and be supported by rustc. It still requires writing some asm in a function, but permits non-asm code in naked functions as well. |
I think @nikomatsakis meant |
Are there use cases beyond naked functions? EDIT: I mean, are there use cases that cannot be addressed by naked functions? |
@nikomatsakis Not really, I think it just means you can write
instead of
|
@nikomatsakis It also allows you to include external asm files by using |
Possibly some data is easier to define in assembly, but I cannot think of any example off-hand. Naked functions would be a poor way to define statics. |
I think even there you could put it in an
Yes a vector table often has to be done in assembly, which I've had to do with a useless naked function. It works but it's an ugly hack and I am very much in favour of this RFC. |
@parched A "vector table"? Could you not do that with Rust types? |
@eddyb No, because its just aligned bits of code. So, unless you manually encode the instructions into an array, you can't do it in rust. |
Yeah, I consider a "useless naked fn" to be a pretty big hack. I mean, it works, but... So, this example tilts my opinion to being roughly in favor of this RFC. It seems like a good fundamental capability. Also, it's worth nothing that when we accepted naked fns, we did so on an explicitly experimental basis. This seems to imply it's worth adding some alternatives (even if they overlap) so that, later, we can assess the ways in which those are being used and try to decide between them. And there are definitely known problems with naked fns (at least those that contain anything other than a single One question I had: if you wanted to define a naked fn that could also be called from Rust code, could you do it with a |
I've done this before in C, all you need to do is export the symbols from the asm using |
Actually I did do something similar in Rust, except it involved symbols generated by a linker script rather than by asm: extern "C" {
static <symbol>: u8;
} |
I've done this with a macro in the past, it's not too bad https://github.com/intermezzOS/kernel/blob/master/src/interrupts/src/lib.rs#L16-L76 |
@steveklabnik It's a bit trickier on aarch64:
|
I looked at my code again, and actually my AArch64 vector table naked function wasn't so useless because I put it in its own section and aligned it in liker script which meant I used the function as the base address of the vector. So it does actually look like a callable function with lots of dead code after the first entry. Something that would be useful here is exposing LLVM's function alignment attribute, so it doesn't need to placed in its own section and aligned with the linker.
As @Ericson2314 pointed out, disadvantage of |
Having said that though, rust could easily have is own extended |
Huzzah! We discussed this again in the @rust-lang/lang meeting and this time decided to accept this RFC. The general idea is that this is explicitly an experimental feature, similar to naked fns, with the goal of gaining experience in this area so we can have a better idea what our story ought to be. Some questions that would be good to address in the implementation:
|
Tracking issue: rust-lang/rust#35119 If you'd like to keep following the development of this feature, please subscribe to that issue, thanks! :) |
Example:
Rendered