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 the start
feature
#29633
Comments
I believe the semantics of this today are that the compiler will generate a function with the symbol The signature for this function is also |
On Windows the executable entry point does not take any arguments. Currently we let the CRT act as the executable entry point which then calls our Rust entry wrapper which invokes the start function which is either |
html5ever uses in an ugly hack that overrides the This would be better solved by some way to override the test harness used by |
@SimonSapin the use case for that with Cargo should in theory be |
The Is there a tracking issue for |
Oh that's already implemented today, if a test target is listed as (this may be a bit off-topic from |
The current signature for the lang item is fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize { which is called by a generated main function. Instead, the signatures of both should be arbitrary and the symbols translate to |
Note that on windows it really shouldn't always be |
#20064 suggests that the signature here is wrong, we should consider this before making this feature stable. |
Just to clarify, it's not just a question of what signature
Of course this would be an easy fix. |
Just don't stabilize this until consideration is taken for subsystems, which change the entry point completely from |
Entry point name is irrelevant for windows apps actually. Ability to specify subsystem is one of important things to create application, because most of them are gui with "windows" subsystem. |
Fix native main() signature on 64bit Hello, in LLVM-IR produced by rustc on x86_64-linux-gnu, the native main() function had incorrect types for the function result and argc parameter: i64, while it should be i32 (really c_int). See also #20064, #29633. So I've attempted a fix here. I tested it by checking the LLVM IR produced with --target x86_64-unknown-linux-gnu and i686-unknown-linux-gnu. Also I tried running the tests (`./x.py test`), however I'm getting two failures with and without the patch, which I'm guessing is unrelated.
Pinging this thread since it seems inactive. I wanted to express interest in this feature being stabilized. I was really excited when I discovered that you could replace the entry point in Rust, and then real bummed when I found out that you could only do it on nightly. |
It's also necessary to write #![no_std] programs. |
I would expect |
Speaking of which… is there any reason for this? We could make a version of Personally, instead of offering |
@glandium The binary entry point is completely different from @clarcharr Adding some form of |
I've just been using I just define my main function with |
@retep998 Oh, I didn't know that. I think that in that case, it makes sense to simply have a That was initially the idea but I didn't realise how windows did things. |
Indeed, it surprisingly works on linux, mac and even windows, with a |
#![no_main]
#[no_mangle]
pub fn main(args: Vec<String>) {
for arg in args {
println!("{}", arg);
}
} |
The current signature for |
On way to implement a plattform specific design is to have a |
I think this issue is the best place to discuss something I haven't really seen brought up anywhere, in fact @nacaclanga is the first person I've seen mention the idea of an intrinsic to initialize the runtime from a custom main function, which would certainly have solved an issue I've encountered. My use case is in an ahead-of-time compiler, written in Rust, that compiles Erlang source code to a native executable (or if desired, to a static/dynamic lib), and links against a runtime, also written in Rust, that provides the "real" entry point of the executable. The compiler is based on LLVM, and its linker is largely based on the Rust linker. The issue I ran into relatively far into the implementation, was the question of how to link my Rust runtime to the executable generated by the compiler while ensuring that the Rust standard library runtime gets properly initialized. Put another way, I want the executable to start as if it was compiled by rustc with my runtime crate as the entry point. I found a way to make it work, but dear lord is it disgusting: NOTE: This is currently being compiled against a slightly older version of Rust, and I imagine there has been enough movement upstream that this no longer compiles as-is on the most recent nightly without a few changes, but the point is just to convey what I've had to do to handle this. I'm just getting back into it recently after having been away for most of this year. ///! This code is from the core runtime crate, it is linked in to compiled executables to act as the main entry point
#![feature(main)]
mod atoms;
mod symbols;
extern "Rust" {
/// We support linking against different high-level runtime implementations, they are required to
/// export an `rt_entry` function.
#[link_name = "rt_entry"]
fn rt_entry() -> i32;
/// The symbol `__rt_lang_start_internal` is generated by our compiler by first discovering the
/// name of the real Rust lang_start_internal symbol of the Rust toolchain it is built against, and then generating
/// code to act as a shim for calling that symbol, but exported with a consistent name
#[link_name = "__rt_lang_start_internal"]
fn lang_start(main: &dyn Fn() -> i32, argc: isize, argv: *const *const i8) -> isize;
}
#[no_mangle]
pub extern "C" fn main(argc: i32, argv: *const *const std::os::raw::c_char) -> i32 {
unsafe { lang_start(&move || main_internal(), argc as isize, argv) as i32 }
}
/// The primary entry point for our runtime
///
/// This function is responsible for setting up any core functionality required
/// by the higher-level runtime, e.g. initializing the atom table. Once initialized,
/// this function invokes the platform-specific entry point which handles starting
/// up the scheduler and other high-level runtime functionality.
#[main]
pub fn main_internal() -> i32 {
use crate::atoms::*;
use crate::symbols::*;
// Initialize atom table
if unsafe { InitializeAtomTable(ATOM_TABLE, NUM_ATOMS) } == false {
return 102;
}
// Initialize the dispatch table
if unsafe { InitializeDispatchTable(SYMBOL_TABLE, NUM_SYMBOLS) } == false {
return 103;
}
// Invoke platform-specific entry point
unsafe { rt_entry() }
} This honestly isn't even the worst part, that award probably goes to what I do to extract the real I'm a bit surprised this isn't a more commonly requested use case, particular for ahead-of-time compiler projects. I wouldn't be surprised if there are other situations in which you want to compile a Rust crate as a library that can be linked together with other code to form an executable while retaining the ability to properly initialize the standard library. I'm entirely unclear on how this can work at all today with Rust crates that are linked into C/C++ programs, perhaps it doesn't, or maybe the functionality used by those programs don't depend on standard library features that require initialization (is that even possible?). In my case, I rely on things like the ability to ask for args passed to the executable, the panic handler, the main thread setup + stack guard, etc., for my runtime. Right now (AIUI) the situation is basically all or nothing, you either compile your binary with I hope this is the right place for bringing this up, and that having an example of a concrete use case is helpful in further discussions of this type. If you have noticed something that I seem to be missing, definitely let me know, if I can do what I want to do within the bounds of currently supported features, I'm all ears. For now, I'm just crossing my fingers that my dirty hack continues to work until a more permanent solution becomes available. |
We'd like to stabilize this, but we need to evaluate the function signature and what commitments we make for which parts of the standard library work. |
I would also like to have a way to define a custom function that replaces the I am currently trying to port the #[export_name = "efi_main"]
pub extern "C" fn main(_h: efi::Handle, st: *mut efi::SystemTable) -> efi::Status {
...
} I would like the users to be able to just use the normal So I do hope that we can get a standardised way to achieve this, since most of the firmware development probably doesn't care about the arguments passed/ |
The following interesting testcase came up in #97049 related to this feature: #![feature(start)]
#[start]
fn start(_: isize, _: *const *const u8) -> isize { panic!(); } I think this program has UB, since there is no Rust runtime here to catch the panic, meaning we are unwinding past the top of the stack. So this should be noted somewhere with the documentation of this feature. |
This can easily be solved by making the |
And then the automatic abort-on-unwind logic will kick in? Yeah, that makes sense -- but would also need documentation. |
10066: ANN: Add support for E0131, E0197, E0203 r=vlad20012 a=kuksag <!-- Hello and thank you for the pull request! We don't have any strict rules about pull requests, but you might check https://github.com/intellij-rust/intellij-rust/blob/master/CONTRIBUTING.md for some hints! Also, please write a short description explaining your change in the following format: `changelog: %description%` This description will help a lot to create release changelog. Drop these lines for internal only changes :) --> changelog: * Add support for E0131 Error code reference: https://doc.rust-lang.org/error_codes/E0131.html There's a feature that might be connected to this error code: rust-lang/rust#29633 * Add support for E0197 Error code reference: https://doc.rust-lang.org/error_codes/E0197.html * Add support for E0203 Error code reference: https://doc.rust-lang.org/error_codes/E0203.html Compiler implementation: https://github.com/rust-lang/rust/blob/master/compiler/rustc_hir_analysis/src/astconv/mod.rs#L877 Co-authored-by: kuksag <georgiy.kuksa@gmail.com>
From the original post:
Has anyone actually used this successfully for the purpose stated above? From my testing (using bare-metal targets), it doesn't seem to define the entry point at all. It silences the following error: "error: requires What advantage does this (as currently implemented) even provide over using |
It defines the |
So, if I understand you correctly, you're saying that the description of this feature is wrong — that it was never intended to override the entry point at all, but to override the Also, if it's meant to be called from the CRT, shouldn't it require an |
Rustc actually won't rename the function annotated with |
That still makes wording like "indicates a function should be used as the entry point" ambiguous at best, and very confusing (as can be seen in previous discussions in this tracking issue). My suggestion, now that I understand what this feature is really intended for, is simply that the description of this feature needs to be clarified.
As far as I understand, Windows still has an entry point equivalent to
Ah, I see. |
I think this issue should be closed and I think the way the stable user-facing entrypoint should work (and works today on stable) is pretty simple:
|
Miri currently relies on |
Lang-nominated for the proposal in #29633 (comment) |
@Nilstrieb how would you propose projects that need to initialize the Rust runtime as I described in #29633 (comment) and subsequently raised by @Ayush1325? As far as I can tell, there is still no solution for this, and because much of what is handled by I'm a bit surprised that there has been zero discussion around use cases like this, as rare as they may be, it is still something that someone providing their own crt0/ Anyhow, wanted to bring this up one last time before this thread effectively dies. |
That is probably best handled with a new RFC cycle to hammer out the details. |
@bitwalker it you're an AOT compiler you can just hook C main by overriding it with your own and then calling the C main defined by Rust (with some trickery). No language feature required. |
Tracking issue for
#[start]
, which indicates that a function should be used as the entry point, overriding the "start" language item. In general this forgoes a bit of runtime setup that's normally run before and after main.Open questions
The text was updated successfully, but these errors were encountered: