I know that programs compiled for native Windows have a format called Portable Executable (PE) and that allows the operating system to load the program into memory.
But I am intrigued by the process by which it is loaded into memory and then executed, that is, it happens from when I click inside the explorer process until the windows of the application itself are created by calling winmain (this is done within the code of the program as in the documentation ):
LONG APIENTRY MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
What happens between these two events?
The process is relatively simple to explain, but not so simple to carry out .
First of all: CPUs have a series of requirements to be able to execute any piece of code: certain registers have to point to valid memory addresses.
Additionally, the rules imposed by the Operating System on duty must be complied with: a certain piece of memory can only be accessed by a certain program, and in a certain way (read, write, execute).
The basic execution process (not loading) consists of preparing the CPU's memory and registers to meet the imposed requirements. This is carried out by the Operating System .
For the above, certain data of the file to be executed are consulted.
Once the memory is prepared, the code itself is loaded , each portion in the necessary part. Program data segments are loaded into the dedicated data memory area, executable code segments into the code area, ...
Here, the charging thing can be misleading. Through the process of "memory file mapping" , the aforementioned loading can be postponed until the CPU does not actually need to access the memory area in question.
Once the code is loaded , it is dynamically linked . That is, the segment of the file that contains the name of the libraries
.dll
that are needed is consulted. Some will already be loaded (in shared memory zones, running for everyone). Others do not, and it will be necessary to repeat the loading process for them (with their peculiarities; for example, libraries do not need a stack ).At last, everything is loaded (or *memory mapped). Now, you have to overwrite the points in the program code where certain imported functions are called, by their actual addresses.
This is also misleading . There are mechanisms to avoid having to traverse the entire memory , using memory zones as intermediate tables . The end result, however, is the same: all calls to
.dll
point to the desired code.Now, yes, you can start the execution of the program, forcing the CPU to create a new process, and using the memory areas that have been prepared with so much care .
Normally, the execution itself doesn't go directly to the function
WinMain
, ormain
, or whatever. A piece of code placed by the compiler is first called, which is responsible for performing data initialization tasks. In C++, for example, it is this pre-main code that takes care of calling static instance constructors.Yes now; Finally, we call our
WinMain( )
.One of the things we can do inside
WinMain( )
is register our window function , which will be used by Windows to deliver the messages. These messages are generated independently of us , most of them are artificial (generated by the system itself). But that is another topic, and will be told on another occasion...