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 global-asm support (RFC 1548) #35119

Closed
nikomatsakis opened this issue Jul 29, 2016 · 49 comments
Closed

Tracking issue for global-asm support (RFC 1548) #35119

nikomatsakis opened this issue Jul 29, 2016 · 49 comments
Labels
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: An issue tracking the progress of sth. like the implementation of an RFC S-tracking-ready-to-stabilize Status: This is ready to stabilize; it may need a stabilization report and a PR T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@nikomatsakis
Copy link
Contributor

Tracking issue for global_asm! macro rust-lang/rfcs#1548:

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

Feedback on its design is required, as well as comparisons with naked fns.

@jackpot51
Copy link
Contributor

jackpot51 commented Jul 29, 2016

Don't take away naked functions!!!!!!!!!!!!!!!!!!!

They are a crucial component of building operating systems in Rust.

Without naked functions, it is impossible to do context switching without moving huge amounts of code into assembler. Converting such code to global_asm! is unnecessary, insecure, difficult to read and modify, and requires repeating code for each target.

@nikomatsakis
Copy link
Contributor Author

@jackpot51 more detailed examples would be great :)

@nikomatsakis
Copy link
Contributor Author

@jackpot51 but rest easy, I don't think we're in any hurry to make firm decisions here. :)

@ticki
Copy link
Contributor

ticki commented Jul 29, 2016

@nikomatsakis They're used in anything from interrupt handler to context switches. I would cry for 10 years straight if you removed them.

@steveklabnik
Copy link
Member

To make this concrete, here is a PR where I went from regular old asm to naked fn: https://github.com/intermezzOS/kernel/pull/49/files

All that setup code in src/src/asm/interrupt_handlers.asm was able to go away; the duplication between the extern declarations in src/interrupts/src/lib.rs was able to go away... much, much, much nicer.

@jackpot51
Copy link
Contributor

Thanks @steveklabnik for showing the potential of #[naked]. Our experience in Redox was similar

@parched
Copy link
Contributor

parched commented Jul 29, 2016

Regarding having compile time constants and unmangled labels in it, would it possible to have separate procedural macro that did this? Something like unmangle!(ident) and eval!(expr) that produced string literals. Or is that not possible?

If a general way like that wouldn't work then something like the way armcc does it would be good.

@nagisa
Copy link
Member

nagisa commented Jul 29, 2016

I do not see how any naked function is not trivially convertible to a global_asm! or vice-versa, though (examples pointing out the contrary much appreciated). For example, you could have a naked! { fn peach() { /* asm goes here */ } which expands to global_asm! as an implementation of naked functions. Making global_asm! just a wrapper over naked functions seems also plausible to some extent.

Otherwise, I agree with Niko, that nobody is making any decisions anytime soon, but would like to add that seeing quality of naked function implementation, its future looks bleak.

@eternaleye
Copy link
Contributor

eternaleye commented Jul 29, 2016

@nagisa: I agree with you on naked-functions-on-top-of-global_asm!, but I actually disagree on the inverse.

In particular, it relies on doing awful Duff's Device-like tricks, where asm that's syntactically inside a function is treated semantically as if it was global.

If Rust ever grows a principled handling of inline asm, that sounds like an immense obstacle and/or footgun.

@alexcrichton alexcrichton 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. labels Aug 1, 2016
@nikomatsakis
Copy link
Contributor Author

On Fri, Jul 29, 2016 at 03:49:10PM -0700, eternaleye wrote:

@nagisa: I agree with you on naked-functions-over-global_asm, but I actually disagree on the inverse.

To clarify: do you mean "simulating global asm using a dummy naked function is a hack"?

@eternaleye
Copy link
Contributor

eternaleye commented Aug 2, 2016

@nikomatsakis

To clarify: do you mean "simulating global asm using a dummy naked function is a hack"?

In essence, yes - I feel using naked functions to simulate global asm is a hack, and one that could easily be broken by non-rustc parts of the compilation process to boot.

@whitequark
Copy link
Member

I am in favor of this feature. My problem is that I need to use ARM EHABI directives inside assembly, however LLVM does not support them inside call asm instructions, and there is no workaround (specifically, .save must come after .fnstart but the context of call asm is as-if there was no .fnstart so it asserts in the parser; and I cannot specify .fnstart inside the call asm itself since it would break in a similar way after codegen then).

Of course, this is just one particular bug in LLVM (that I'm not going to fix, personally, I have better things to do). Even if it was fixed, however, I am sure there are other instances where assembly within a naked function does not behave in the same way as module-level assembly, and it would be unwise to assume that all problems related to those can be worked around. If they have to be fixed upstream, then there is at least a year of delay before the fix trickles down and the crate becomes usable on crates.io.

@brson brson added B-unstable Blocker: Implemented in the nightly compiler and unstable. and removed B-unstable Blocker: Implemented in the nightly compiler and unstable. labels Mar 1, 2017
@mrhota
Copy link
Contributor

mrhota commented Mar 13, 2017

btw, visitors from the future, I'm working on this.

frewsxcv added a commit to frewsxcv/rust that referenced this issue Apr 5, 2017
Implement global_asm!() (RFC 1548)

This is a first attempt. ~~One (potential) problem I haven't solved is how to handle multiple usages of `global_asm!` in a module/crate. It looks like `LLVMSetModuleInlineAsm` overwrites module asm, and `LLVMAppendModuleInlineAsm` is not provided in LLVM C headers 😦~~

I can provide more detail as needed, but honestly, there's not a lot going on here.

r? @eddyb

CC @Amanieu @jackpot51

Tracking issue: rust-lang#35119
frewsxcv added a commit to frewsxcv/rust that referenced this issue Apr 6, 2017
Implement global_asm!() (RFC 1548)

This is a first attempt. ~~One (potential) problem I haven't solved is how to handle multiple usages of `global_asm!` in a module/crate. It looks like `LLVMSetModuleInlineAsm` overwrites module asm, and `LLVMAppendModuleInlineAsm` is not provided in LLVM C headers 😦~~

I can provide more detail as needed, but honestly, there's not a lot going on here.

r? @eddyb

CC @Amanieu @jackpot51

Tracking issue: rust-lang#35119
frewsxcv added a commit to frewsxcv/rust that referenced this issue Apr 12, 2017
Implement global_asm!() (RFC 1548)

This is a first attempt. ~~One (potential) problem I haven't solved is how to handle multiple usages of `global_asm!` in a module/crate. It looks like `LLVMSetModuleInlineAsm` overwrites module asm, and `LLVMAppendModuleInlineAsm` is not provided in LLVM C headers 😦~~

I can provide more detail as needed, but honestly, there's not a lot going on here.

r? @eddyb

CC @Amanieu @jackpot51

Tracking issue: rust-lang#35119
frewsxcv added a commit to frewsxcv/rust that referenced this issue Apr 12, 2017
Implement global_asm!() (RFC 1548)

This is a first attempt. ~~One (potential) problem I haven't solved is how to handle multiple usages of `global_asm!` in a module/crate. It looks like `LLVMSetModuleInlineAsm` overwrites module asm, and `LLVMAppendModuleInlineAsm` is not provided in LLVM C headers 😦~~

I can provide more detail as needed, but honestly, there's not a lot going on here.

r? @eddyb

CC @Amanieu @jackpot51

Tracking issue: rust-lang#35119
@mark-i-m
Copy link
Member

One other data point: I find myself still using a .S file and manually invoking the assembler and linker because I want to position certain sections of the binary at certain locations.

This gives me the idea of turning global asm into a new attribute:

#[cfg(target-arch=“x86-64)]
#[asm(“arch/entry.S, linker-args=“...”)]

@gz
Copy link
Contributor

gz commented Apr 18, 2019

FWIW passing .S files to rustc seems like a good way to go about it, without introducing language features/complexity for such (arguably niche) situations.

@GuillaumeDIDIER
Copy link

Is there any difference between having global_asm! and having rustc able to eat .S files. I think the issues with either one are the same, and that supporting either or both is probably the same work.

(But I may be mistaken).

Consequently why not support both.

@jonas-schievink jonas-schievink added B-RFC-implemented Blocker: Approved by a merged RFC and implemented. B-unstable Blocker: Implemented in the nightly compiler and unstable. and removed B-RFC-approved Blocker: Approved by a merged RFC but not yet implemented. labels Nov 26, 2019
@Aaron1011
Copy link
Member

How (if at all) does this interact with inline ASM?

@mark-i-m
Copy link
Member

It seems pretty orthogonal to me. IIUC, it uses a different LLVM feature altogether. I suppose one could define labels in a global asm and reference them from inline asm, though...

@luojia65
Copy link
Contributor

luojia65 commented Jul 11, 2020

This is very useful in operating system development. I may define global entry in producal macros:

#[proc_macro]
pub fn boot_page_sv39(item: TokenStream) -> TokenStream {
    println!("{:?}", item);

    quote!(
        #[repr(align(4096))]
        #[repr(C)]
        struct __BootPage([usize; 512]);
        #[export_name = "_boot_page"]
        static __BOOT_PAGE: __BootPage = __BootPage([0; 512]);
        global_asm!("...");       // <- entry assembly code
    ).into()
}

Which could be more convenient.

@Mic92
Copy link
Contributor

Mic92 commented Dec 18, 2020

Is it possible to generate position independent code with global_asm?

I tried

#[cfg(target_arch = "x86_64")]
global_asm! {r#"
.global _start
_start:
  mov %rdi, %rsp
  call main
"#}

However the main address it not position independent which causes a segfault at runtime.
This is possible with naked functions:

 #[no_mangle]
 #[naked]
 pub unsafe fn _start() {
   // call here is pic
   #[cfg(target_arch = "x86_64")]
   asm!("mov rdi, rsp", "call main");
 }

@Mic92
Copy link
Contributor

Mic92 commented Dec 18, 2020

Never mind. my actual issue was is that inline asm is using intel syntax, while global_asm is using gas. So this is the fix:

#[cfg(target_arch = "x86_64")]
global_asm! {r#"
.intel_syntax noprefix
.global _start
_start:
  mov rdi, rsp
  call main
"#}

@jgouly
Copy link

jgouly commented Jan 29, 2021

It would be nice if global_asm!() could support specifiers like sym/const that the inline asm!() does. This would allow using symbol names in global_asm!() without using #[no_mangle] and using size_of::<Struct>() without hardcoding the values.

@eddyb
Copy link
Member

eddyb commented Feb 4, 2021

Noticed the error reporting was suboptimal and filed #81751 (but there might not be anything to be done without changing LLVM).

@dancrossnyc
Copy link

global_asm!() now supports at least const parameters, which is really cool, but also surprising if you're using it with include_str!() to bring in, say, a .S file that has a comment that includes curly braces. It would be really awesome if there were some way to assert that a particularly invocation of the macro didn't need or want expansion....

@Amanieu
Copy link
Member

Amanieu commented Jun 24, 2021

@dancrossnyc I've added a raw option in #86599 which should address this problem.

@dancrossnyc
Copy link

Thank you so much!

@wrenger
Copy link

wrenger commented Aug 18, 2021

I am trying to convert my att asm to intel (for use with global_asm from 1.56.0-nightly (25b7648 2021-08-04)), but i am not really able to convert the x86 long jump instruction:

.att_syntax
   	ljmp $0x8, $start_high

So far i tried: jmp 0x8:start_high, ljmp 0x8, start_high or jmp 0x8, start_high...

Any ideas?

PS: This is very x86 os specific and it could be an llvm problem. So this discussion may be the wrong place for that, sry if that's the case.

@dancrossnyc
Copy link

Note: this doesn't address the question about Intel syntax for a long jmp, but if it's easier, global_asm! supports options(att_syntax) so that you can continue using AT&T syntax if you like.

@Amanieu
Copy link
Member

Amanieu commented Aug 19, 2021

I think the syntax is jmp far 0x8:start_high.

@wrenger
Copy link

wrenger commented Aug 19, 2021

Note: this doesn't address the question about Intel syntax for a long jmp, but if it's easier, global_asm! supports options(att_syntax) so that you can continue using AT&T syntax if you like.

Well I like the intel syntax more, but I am considering it. Currently I'm switching syntax only for this instruction with .att_syntax, which isn't that great either.

I think the syntax is jmp far 0x8:start_high.

Unfortunately this also fails with an unknown token error (similar to jmp without far).

error: unknown token in expression
   |
note: instantiated into assembly here
  --> <inline asm>:58:13
   |
58 |     jmp far 0x8:start_high
   |                ^

@ketsuban
Copy link
Contributor

Currently I am using global_asm in the simple form documented by the Rust Unstable Book, to include an external assembly file containing a header whose integrity is checked by the firmware on startup and some initialisation code which calls my main function. It is absolutely the best tool for the job short of rustc consuming external assembly files directly - using a naked function, while possible, would be a mess of workarounds since the code never gets called from Rust.

@phip1611
Copy link

Is there any documentation available on what assembler-flavor global_asm is using? In my experiments, it seems that it's the same for all platforms, i.e. Linux and Windows. It looks to me like it's just GAS with intel syntax. Is this true or is it only similar to GAS with intel syntax?

I think there should be better documentation of what assembler flavor is used and a link to additional documentation should be provided. So far I don't know if rustc forwards it to the "default assembler compiler of the system" or if LLVM can take care of it.. I'd love to know about this!

@Amanieu
Copy link
Member

Amanieu commented Dec 20, 2021

It always uses a GAS-like syntax with intel syntax on x86. This is done using LLVM's internal assembler and not by actually invoking GAS.

The documentation is in the process of being added to the reference here.

@joshtriplett
Copy link
Member

@Amanieu Is this the tracking issue being used for the current global_asm! (that's consistent with asm!), or is that being tracked for stabilization elsewhere?

If the latter, we should close this in favor of wherever that's being tracked.

@joshtriplett joshtriplett added the S-tracking-ready-to-stabilize Status: This is ready to stabilize; it may need a stabilization report and a PR label Jan 19, 2022
@Amanieu
Copy link
Member

Amanieu commented Jan 19, 2022

global_asm! is now stable, so this can be closed.

@Amanieu Amanieu closed this as completed Jan 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
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: An issue tracking the progress of sth. like the implementation of an RFC S-tracking-ready-to-stabilize Status: This is ready to stabilize; it may need a stabilization report and a PR T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests