4 ms·
> Things that I don’t understand very well, including calling main. So I won’t explain them. It depends on the language runtime, but a common task will be init
by vlovich123 3y ago
> Things that I don’t understand very well, including calling main. So I won’t explain them.
It depends on the language runtime, but a common task will be initializing global non-0 statics. For languages like Rust/C/C++ you can also inject variables to be initialized via linker flags. Before start if the program is dynamically linked then I believe the linker runtime is run to resolve the links and then transfer control to _start.
Basically hacks on hacks on hacks added organically to offer extensibility and the hacks have enough social adoption and are good enough that we stick with them.
- seanw444 3y ago> Basically hacks on hacks on hacks added organically to offer extensibility and the hacks have enough social adoption and are good enough that we stick with them. The more I learn about the deep depths of modern computing, the more I realize that they're actually full of inelegant legacy cruft.
- kccqzy 3y agoThe style guide at both my previous and current employers explicitly forbids having global non-0 statics for this exact reason: code that runs before main() is very unusual. Many assumptions do not hold. A far better way is to use function-local statics. A static variable inside a function is initialized when execution reaches that point when the function is being called. Furthermore, such initialization is thread safe so that one initialization happens despite multiple concurrent calls of the function. The only exception to that style guide rule is the new constinit in C++20. It is sometimes called linker-initialized to make it even clearer that the program didn't do anything to initialize it, the linker did.
- cesarb 3y ago> Furthermore, such initialization is thread safe so that one initialization happens despite multiple concurrent calls of the function. IIRC, there are some popular compilers in which initialization of static variables inside functions is not thread safe (even though AFAIK the C++ standard said they should be).
- vlovich123 3y agoI’m not aware of this problem in MSVC, clang and gcc and those are the most popular afaik.
- cesarb 3y ago> I’m not aware of this problem in MSVC The compiler I was thinking of was indeed MSVC. From a quick web search, it seems that more recent versions of MSVC have changed them to be thread safe by default, so if you can make sure that your code will never be compiled on older MSVC versions (and that nobody will ever use the compiler option which disables the thread-safe initialization), it might be fine to depend on it.
- vlovich123 3y agoTrue as of msvc 2015 which is 8.5 years old at this point. I agree it’s weird that you can disable it but libraries retaining correctness in the face of random compiler flags is hard (eg ffast-math is a common one that can break your floating point library)
- secondcoming 3y agoThe issue with Meyers Singletons is that every time they're accessed a flag must be checked first. This is bad in hop loops.
- vlovich123 3y agoIt’s not as bad as you might think because the CPU should speculate through it pretty easily.
- matheusmoreira 3y ago> initializing global non-0 statics Does that mean this doesn't work in a freestanding environment? Yet another reason to assiduously avoid global variables. I suppose that's why I never ran into this issue. > Basically hacks on hacks on hacks And then there's this insanity right here: https://blogs.oracle.com/solaris/post/init-and-fini-processing-who-designed-this https://blogs.oracle.com/solaris/post/init-and-fini-processi... I like to imagine that I won't have to actually implement this when I write my ELF loader. Someone please tell me no modern software uses this.
- vlovich123 3y ago> Does that mean this doesn't work in a freestanding environment? Yet another reason to assiduously avoid global variables. I suppose that's why I never ran into this issue. Why do you say that? A freestanding environment will still enter through _start and execute the compiler generated code to initialize globals before main. What I can’t recall is how compile time non-0 values are initialized - I think it could be part of the bss and initialized by the loader instead (but freestanding environments would implement that too as part of being a target for a language) but both them and runtime initialized globals initialized between _start and main would work. Basically freestanding targets might not give you access to runtime APIs (eg POSIX) but the language is still the language and all features defined as language features should work and it’s the responsibility of the compiler and target environment to provide that guarantee.
- matheusmoreira 3y ago> Why do you say that? Your post gave me the impression the compiler generates initializers for static globals and calls them during program initialization. Is this not correct? > A freestanding environment will still enter through _start and execute the compiler generated code to initialize globals before main. Freestanding C generally implies not linking in any standard library code though. It doesn't make any sense to choose the freestanding C dialect only to link in the standard hosted C library. The _start symbol is provided by the C library's so called standard system startup files. The standard _start calls all the initialization functions that the C program expects. If you override it with your own _start, then none of these functions will be called. I thought you meant the static data initialization was handled in one of these functions.