It depends on the operating system, in general. Some don't load the first code page, but let the load-on-demand system handle that!
The ABI does determine the state of the user program at the point where its entry is invoked. There may or may not be a user stack set up.
In the SysV ABI for x86-64 follow, the user state is, roughly, this:
- There is a user stack set up.
*argv
and *envp
have been pushed on that stack.
- Four specific registers contain
argc
, argv
, envc
, and envp
.
It is then up to the runtime for the programming language to set everything else up. We'll use C as our example. The relevant part of the runtime is called crt0 or c0 (short for C runtime, and the 0 means "very first"). The typical jobs that it has to do are:
- Set up the heap, signal handlers, the handler for
atexit
, etc.
- Set up exception handling and run global constructors if this is C++.
- Invoke
main
.
- On return from
main
, call exit
.
One important difference in Windows is that the command-line is a single string; you can see this by looking at WinMain
. So if you are writing a program that uses main
as its entry point, the C runtime parses the command line for you.
As for zeroing pages, that is generally correct. The program file in a modern operating system is built from a number of segments. They are, typically:
text
, which is a part of the file that is mapped as read-only and executable. This corresponds to executable code.
rodata
, a part of the file mapped as read-only. This corresponds to read-only data (e.g. static string data, virtual dispatch tables, etc).
data
, a part of the file mapped as read-write and copy-on-write. This corresponds to statically initialised read-write data.
bss
, which is a region of memory mapped as zero-fill. This corresponds to uninitialised read-write data; because it is uninitialised, there does not need to be an image of this data stored in the program file.
The term "bss" was originally a pseudo-assembly instruction for the IBM 704, which meant "block started by symbol". The connection between this and the modern usage is tenuous and not relevant; Peter van der Linden suggested that you can think of it as "better save space".
Stack and allocated heap memory is also zero-fill. This is literally the case in some operating systems, where heap is allocated by memory mapping the special file /dev/zero
, but in POSIX-like operating systems you can almost always map anonymous memory directly, or there is a special system call (e.g. VirtualAlloc
in Windows, vm_allocate
in Mach/macOS). The semantics are always that new regions are zero-filled.
(EDIT: Thanks to Peter Cordes for correcting one mistake in the last paragraph.)