Are TLS and spawning threads allowed before the C runtime is initialized? If not, then Rust needs the C runtime to be initialized.
Long story short, the win32 loader creates the initial thread and runs a function called
LdrInitializeThunk before the exe's (or dll's) entry point. This function is part of the OS, not the binary. As far as I'm aware, this function does all the necessary initialization for threads, TLS, etc. So for those keeping score, the functions before
LdrInitializeThunk: sets up a win32 process/thread
mainCRTStartup: Entry point. Initializes the CRT
lang_start: Initializes Rust's std.
main: The Rust program's main.
I think it should be possible for Rust to set the entry point to
lang_start (which is exported as main), therefore skipping
mainCRTStartup. But I'm not 100% certain the C initialization isn't doing anything useful for Rust, hence my question.
I think Rust code could be linked with C/C++ static libraries that need the CRT, and also I think it's legitimate to actually have global constructors in Rust code (albeit unsafe and with inline asm or a C/C++ helper), so it seems problematic to unconditionally not initialize the CRT, and thus it probably needs to be an opt-in option and probably still need to have code to call global constructors.
According to http://zetcode.com/gui/winapi/main/ mainCRTStartup initializes file IO support and other things, so it would not be possible to omit it even when only using rust code and no C code.
That link confuses me. What memory management and file IO needs to be set up for C/C++ on Windows? Perhaps that's talking about managed code? Also this is more of a nitpick but the Windows C++
main function called by
mainCRTStartup has this definition:
int main(int argc, char *argv, char *envp);
Though it is allowed to define it to take no arguments.
The thing is I'm unsure if C itself needs any particular set up on Windows. I know
mainCRTStartup sets up the arguments for
main but Rust doesn't use them. I'm assuming it also does something to run (or set to run) global static constructors which is where I think there could be a problem but I'm unsure of the implementation.
What I've found so far is the Windows CRT initialization does the following:
- Sets argc/argv/envp arguments
- Creates a stack guard
- Initializes dynamic globals
- Run constructors for global C++ objects and set destructors to be run later
The absence of the last two of these would, as bill_myers says, be an issue when static linking C or C++ libraries.
In summary, for a pure Rust
exe the CRT initialization can be skipped (I think) even if calling C functions. However when statically linking C/C++ libraries there may be issues if they use globals that require a function call before main.
For what it's worth, the entire source to mainCRTStartup is shipped with MSVC- in
VC\Tools\MSVC\14.24.28314\crt\src\vcruntime of the installation. You can also get to it by walking up the call stack from main in the VS debugger.
The thing that concerns me about looking at source code or disassembling/debugging is the license. I don't know if having looked at the code could come back to bite me if I do write some code of my own.
Is there something you're trying to avoid by skipping mainCRTStartup? Surely Windows process launch is expensive enough that the time to run mainCRTStartup is in the noise.
Even if it's safe to skip mainCRTStartup today, I would worry about future changes to the CRT invalidating that reasoning.
The license is not a problem. That source is provided explicitly and only for the purpose of reading and debugging it- it is not used by VS for anything else. (i.e. VS doesn't build it to produce the binary form of the vcruntime, it doesn't depend on it itself, etc.)
You can dig up the VS EULA which covers it and the rest of the toolchain, so it falls under the same rules as the compiler/linker/libraries/debugger, which you're already using.
What I mean is that, sure I'm allowed to look at the code. But what if one day I want to write and distribute my own Windows C runtime initializer, outside of VC++? Could my knowledge of Microsoft's code be used to accuse me of violating their copyright? I'd prefer not have to deal with that.
I'm investigating how Rust compiles/links on Windows and how or if the experience could be improved. As part of that I've looking into, for example, how Rust handles imported dll functions and wondering to what extent Rust depends on the Windows C startup routine.
Sure, the ultimate answers may all end up being "keep doing what Rust currently does" but I'd at least like to understand why instead of simply assuming everything has to be the way it is.
I'm definitely not advocating Rust changes anything at this point.
No more than your use of their compiler to build it.
Ok but what if I don't use their compiler or any Visual Studio tools?
That changes nothing. The license is the same- look at "reading the vcruntime source" as an equivalent action to "compiling a program with MSVC."
Avoiding looking at someone else's code can be useful as an affirmative defense if you are accused of copyright infringement. This is a practice known as clean room design. It's probably useful only if you document the entire specification and implementation process sufficiently to prove it in court. If you aren't working with an independent written specification and a knowledgeable legal team, then it's probably not useful to worry about this.
Ah, thanks for the explanation.
If you are using the CRT then you need the CRT entry point. If you statically link to any C/C++ code then you most likely are using the CRT and therefore need the CRT entry point. If you write a pure Rust program where the only C/C++ you touch is in other dlls then you likely don't need the CRT and therefore don't need the CRT entry point. In the future when https://github.com/rust-lang/rust/issues/58713 is finally implemented, Rust will gain a new pure Rust target for windows which won't link to the CRT at all and therefore won't use the CRT entry point.
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.