Register
Handmade Hero»Forums»Code»Guide - How to avoid C/C++ runtime on Windows
16 posts
Guide - How to avoid C/C++ runtime on Windows
4 months, 3 weeks ago
mmozeiko
I checked in MSVC 2019 CRT - it does not call ExitProcess.

WinMainCRTStartup is in "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.27.29110\crt\src\vcruntime\exe_winmain.cpp" file - that simply calls __scrt_common_main() and returns whatever this function returns.

__scrt_common_main is in "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.27.29110\crt\src\vcruntime\exe_common.inl" file - and that simply calls invoke_main in same file (which calls your main) and uses its return value to return back to caller.

So CRT does not call ExitProcess. Maybe exe loader (one that calls WinMainCRTStartup) calls ExitProcess for you - but that is not part of CRT.


exe_common.inl:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
        //
        // Initialization is complete; invoke main...
        //

        int const main_result = invoke_main();

        //
        // main has returned; exit somehow...
        //

        if (!__scrt_is_managed_app())
            exit(main_result);


Isn't that it right there, the CRT exit function?

"[...]the C runtime library automatically calls ExitProcess when you exit the main thread, regardless of whether there are any worker threads still active." - https://devblogs.microsoft.com/oldnewthing/20100827-00/?p=13023

I stepped through the code to look. After returning from WinMain it checks if it's a managed app (__scrt_is_managed_app), it's not, and so it calls the exit function.
Which in my case, is either in the same executable (-MT, app.exit) or ucrtbase.dll (-MD, ucrtbase.exit).

Inside the exit function it eventually called ExitProcess. It looks like it could also call TerminateProcess depending on the "process end policy"
Mārtiņš Možeiko
2175 posts / 1 project
Guide - How to avoid C/C++ runtime on Windows
4 months, 3 weeks ago Edited by Mārtiņš Možeiko on Oct. 8, 2020, 8:53 a.m.
Oh, I'm blind and misread the condition - did not notice ! operator. You're right, for native code it will call exit(...) from this place.
2 posts
Guide - How to avoid C/C++ runtime on Windows
4 months, 3 weeks ago
Thank you both for your investigations.

I suppose that I will simply do like the VS 2019 CRT runtime do and use exit.
Leonardo
18 posts
Guide - How to avoid C/C++ runtime on Windows
2 months, 3 weeks ago
Hey!

Is there something similar to this on Linux? How to avoid all default libraries on Linux?

I know that that is a "-nodefaultlibs" option on Clang (probably on GCC too) in Linux that does the same as "/NODEFAULTLIB", but I have no idea what to do after using it. The entry point, the things I have to replace, stack sizes, etc.

If anyone writes some guide like this for Linux would be awesome!
Simon Anciaux
957 posts
Guide - How to avoid C/C++ runtime on Windows
2 months, 3 weeks ago
Leonardo
18 posts
Guide - How to avoid C/C++ runtime on Windows
2 months, 3 weeks ago
Awesome! Thank you Simon!
Leonardo
18 posts
Guide - How to avoid C/C++ runtime on Windows
1 week, 3 days ago Edited by Leonardo on Feb. 19, 2021, 10:07 p.m.
mmozeiko
4) Global objects with C++ constructors and destructors - it's possible to implement it, but it's not needed for us.


I have a couple of global objects, from a very simple template structure I created for DirectX COM objects, just to take advantage of destructor to call ->Release() in the COM objects, since I hate keeping track of each one I create, and I don't like the warnings that DirectX Debug Layer gives me if I don't Release them. So, without the CRT, I'm having a error LNK2019: unresolved external symbol atexit referenced in function "void __cdecl `dynamic atexit destructor which I can guess is the exact same problem you mention in item 4).

How can I work around this? How to implement atexit? Also, since we use ExitProcess() to exit, how will the destructors be called? Is it where atexit comes in?

EDIT:

I just found the definition of the atexit function:
1
2
3
int atexit(
   void (__cdecl *func )( void )
);


Didn't know it is at stdlib.h
Mārtiņš Možeiko
2175 posts / 1 project
Guide - How to avoid C/C++ runtime on Windows
1 week, 3 days ago
atexit won't be called by anybody if you don't use C runtime. C runtime calls atexit registered function pointers after main returns. Because there's no "main" anymore, there's nothing to call afterwards. You need to manually keep list of function pointers that are registered with atexit and call them yourself. ... or don't call anything. OS will release all process resources on exit anyway.

If you have global objects with destructors, you'll need to implement global destructor stuff to, not only atexit. Otherwise nobody will call global constructors/destructors.

Check out "C:\Program Files (x86)\Windows Kits\10\Source\10.0.19041.0\ucrt\internal\initialization.cpp" file which is part of Universal CRT source code you can install. It is how MSVC runtime does constructors & destructors - "initialize_c" and "uninitialize_c" functions. __xi_a & other symbols are defined in "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\crt\src\vcruntime\internal_shared.h" file.

atexit callbacks are called from "C:\Program Files (x86)\Windows Kits\10\Source\10.0.19041.0\ucrt\startup\exit.cpp" file - with "_execute_onexit_table(&__acrt_atexit_table)"
Leonardo
18 posts
Guide - How to avoid C/C++ runtime on Windows
1 week, 2 days ago
I see, thank you Mārtiņš! I will see what I'm going to do, if it's worth it trying to implement this or I should just Release() each on by hand on exit, or just let the OS do it.

About this: Mārtiņš, do you use DirectX? If yes, do you call Release() for each object or just let the OS release everything and ignore the Debug Layer messages?