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

Open
aturon opened this Issue Nov 5, 2015 · 22 comments

Comments

Projects
None yet
@aturon
Member

aturon commented Nov 5, 2015

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.

@alexcrichton

This comment has been minimized.

Member

alexcrichton commented Nov 5, 2015

I believe the semantics of this today are that the compiler will generate a function with the symbol main which calls the #[start] function, if present, in an executable. This skips the #[lang = "start"] implementation, if any, in an upstream library (the standard library provides this to set up the first catch_panic among a few other minor things).

The signature for this function is also fn(isize, *const *const u8) -> isize, where the isize may no longer be "the most correct". Additionally, the *const *const u8 may not be the most appropriate option for Windows (although it works). I'm not 100% sure what "the best" signature on Windows is.

@retep998

This comment has been minimized.

Member

retep998 commented Nov 9, 2015

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 #[lang = "start"] which then invokes the user's main function pointer provided to it or a user provided #[start] function. Which executable entry point the linker decides to use depends on the /SUBSYSTEM and which main function it can find (https://msdn.microsoft.com/en-us/library/f9t8842e.aspx). All information provided to the main function by the CRT can be obtained through alternative means. Note that if we eventually provide an option for /SUBSYSTEM:Windows that main function takes a very different set of (useless) arguments than the traditional main (https://msdn.microsoft.com/en-us/library/windows/desktop/ms633559%28v=vs.85%29.aspx).

@SimonSapin

This comment has been minimized.

Contributor

SimonSapin commented Dec 18, 2015

html5ever uses in an ugly hack that overrides the main function used by cargo test in order to generate thousands of tests dynamically. (Tests with the same code but parameterized on (input, expected result).)

This would be better solved by some way to override the test harness used by cargo test (Is there an issue/RFC for that already?)

@alexcrichton

This comment has been minimized.

Member

alexcrichton commented Dec 18, 2015

@SimonSapin the use case for that with Cargo should in theory be harness = false, but I'm curious how that interacts with #[start]?

@SimonSapin

This comment has been minimized.

Contributor

SimonSapin commented Dec 19, 2015

The #[start] trick doesn’t work anymore, but it looked like this: servo/html5ever@df8e749

Is there a tracking issue for harness = false?

@alexcrichton

This comment has been minimized.

Member

alexcrichton commented Dec 19, 2015

Oh that's already implemented today, if a test target is listed as harness = false then Cargo just won't pass --test when compiling it and expects it to be a binary.

(this may be a bit off-topic from #[start] though so feel free to ping me on IRC)

@mahkoh

This comment has been minimized.

Contributor

mahkoh commented Jan 7, 2016

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 main directly. This allows the main function to be platform dependent. A pointer to the user's main function can be obtained via an intrinsic.

@retep998

This comment has been minimized.

Member

retep998 commented Jan 7, 2016

Note that on windows it really shouldn't always be main. If the user sets the subsystem to windows instead of console, then the CRT expects to find WinMain which results in a linker error because it wasn't defined.

@steveklabnik

This comment has been minimized.

Member

steveklabnik commented Jun 6, 2016

#20064 suggests that the signature here is wrong, we should consider this before making this feature stable.

@comex

This comment has been minimized.

Contributor

comex commented Jun 7, 2016

Just to clarify, it's not just a question of what signature lang_start should have; rustc currently generates C entry points (main) that only work "by accident" (because on 32-bit platforms isize = c_int and on 64-bit the calling conventions happen to work out). On my Mac, I get:

define i64 @main(i64, i8**) unnamed_addr {

Of course this would be an easy fix.

@retep998

This comment has been minimized.

Member

retep998 commented Jun 7, 2016

Just don't stabilize this until consideration is taken for subsystems, which change the entry point completely from main to WinMain and are really important for Rust to support if it wants to be used in the Windows world (several people have spoken to me and said this is one of the issues getting in the way of them using Rust in production on Windows)

@pravic

This comment has been minimized.

Contributor

pravic commented Jun 7, 2016

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.

@SimonSapin SimonSapin referenced this issue Feb 19, 2017

Open

Tracking issue for 1.0.0 tracking issues #39954

9 of 28 tasks complete

bors added a commit that referenced this issue Oct 1, 2017

Auto merge of #44906 - dkl:main-signature, r=nagisa
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.

bors added a commit that referenced this issue Oct 1, 2017

Auto merge of #44906 - dkl:main-signature, r=nagisa
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.
@AndrewGaspar

This comment has been minimized.

Contributor

AndrewGaspar commented Jan 4, 2018

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.

@glandium

This comment has been minimized.

Contributor

glandium commented Mar 2, 2018

It's also necessary to write #![no_std] programs.

@glandium

This comment has been minimized.

Contributor

glandium commented Mar 2, 2018

I would expect #[start] to pass the /ENTRY argument to link.exe, but it apparently doesn't. Although it's worth noting that the function signature for an entry point on Windows is different anyways, so one would need a different #[start] function there.

@clarcharr

This comment has been minimized.

Contributor

clarcharr commented Mar 5, 2018

It's also necessary to write #![no_std] programs.

Speaking of which… is there any reason for this? We could make a version of Termination for libcore and remove all of the system-specific stuff from the shim. We'd also want some form of env::Args for libcore, but I'd argue that this is reasonable, especially if it's very bare-bones.

Personally, instead of offering #[start], I think that it makes more sense to be able to prune down the existing start shim by removing some of its guarantees. For example, aborting on panics, disallowing multithreading, and disabling stack protection would be enough.

@retep998

This comment has been minimized.

Member

retep998 commented Mar 5, 2018

@glandium The binary entry point is completely different from #[start]. Unless you don't want to link to the CRT at all, you'll probably want the binary entry point to remain the mainCRTStartup provided by the CRT, otherwise the C RunTime won't be initialized!

@clarcharr Adding some form of env::Args to libcore is a bad idea, as on Windows it requires calling system functions and heap allocating which is firmly in the realm of libstd. On the other hand, because it is only a system function, Windows users don't need to ask libcore/libstd for the args and can just go through winapi themselves. Unix users would still need to get argc/argv somehow...

@Amanieu

This comment has been minimized.

Contributor

Amanieu commented Mar 5, 2018

I've just been using #[no_main] in my no_std programs. This completely eliminates the default entry point logic.

I just define my main function with #[no_mangle] and have it called by my initialization code.

@clarcharr

This comment has been minimized.

Contributor

clarcharr commented Mar 5, 2018

@retep998 Oh, I didn't know that. I think that in that case, it makes sense to simply have a MainArgs opaque struct which encapsulates argc and argv or nothing if they're not available.

That was initially the idea but I didn't realise how windows did things.

@glandium

This comment has been minimized.

Contributor

glandium commented Mar 15, 2018

I've just been using #[no_main] in my no_std programs. This completely eliminates the default entry point logic.

Indeed, it surprisingly works on linux, mac and even windows, with a #[no_mangle], pub extern "C" fn main(...) -> isize. (edit: maybe actually i32?)

@japaric

This comment has been minimized.

Member

japaric commented Mar 15, 2018

#[no_mangle] is not type safe so I don't consider it a proper user facing way to set the entry point. It also doesn't require unsafe which makes it not obvious that it's extremely dangerous to get the type signature wrong. This is "safe" and segfaults:

#![no_main]

#[no_mangle]
pub fn main(args: Vec<String>) {
    for arg in args {
        println!("{}", arg);
    }
}
@ketsuban

This comment has been minimized.

Contributor

ketsuban commented Oct 28, 2018

The current signature for #[start] functions isn't great in embedded contexts either. There's nothing to pass arguments to a Game Boy Advance game or read a return value—the only way execution is going to end is if the player switches the game off.

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