Static object, global object and program operation mechanism
1. Before introducing the relationship between static objects, global objects and procedures running mechanisms, let's take a look at the ATEXIT function.
The declaration of the ATEXIT function is: int Atexit (Void) (VOID));
The parameter is a function pointer, and the return value is integer, and 0 is successful, and other indicates fail. When the program runs, he calls all the functions registered with the ATEXIT function. If you call the ATEXIT function multiple times, the system will call all registration functions in a Last-In-First-Out.
For example, the code is taken from the MSDN:
#include
#include
Void Fn1 (Void), FN2 (Void), FN3 (Void), FN4 (Void)
Void main (void)
{
Atexit (fn1);
Atexit (FN2);
Atexit (FN3);
Atexit (FN4);
Printf ("this is executed first./n);
}
Void fn1 ()
{
Printf ("Next./N");
}
Void fn2 ()
{
Printf ("executed");
}
Void fn3 ()
{
Printf ("IS");
}
Void fn4 ()
{
Printf ("this");
}
After compiling, after running the program, the output of the program is:
This is executed first.
This is executed next.
The order in which the registration function is: fn1, fn2, fn3, fn4, but the call sequence is Fn4, Fn3, Fn2, Fn1.
2. After understanding the ATEXIT function, we can take a look at the local static object.
Class aaa {...};
AAA * CREATEAAA ()
{
Static aaa a;
Return & a;
}
In the debug state, the assembly code is as follows (please observe the code from the blue tag):
AAA * CREATEAAA ()
{
...
Static aaa a;
...
[1] 00401056 Call AAA :: AAA (4010A0H)
[2] 0040105B Push Offset `Createaaaaaaaaa ::` 2 ':: A :: `Dynamic Atexit Destructor' (442410H)
[3] 00401060 Call ATEXIT (409A50H)
00401065 Add ESP, 4
00401068 MOV DWORD PTR [EBP-4], 0FFFFFFFH
Return & a;
0040106F MOV EAX, Offset A (452620H)
}
...
00401091 RET
Note: [1], [2], [3] For the convenience of the added characters, there is no exist in the actual code.
[1] The statement is obviously called the constructor of the AAA.
[2] The statement will put the 442410H in the stack.
[3] The statement calls the ATEXIT function, according to our understanding, the parameter of the ATEXIT should be a function pointer. Then let's analyze the code at 442410h. From the comment, we have seen the Destructor. code show as below:
`Createaaa '::` 2' :: A :: `Dynamic Atexit Destructor: ...
[1] 0044242E MOV ECX, OFFSET A (452620H)
[2] 00442433 Call AAA :: ~ AAA (403A90H)
...
0044244B RET
[1] The statement places an address in the ECX register, which is the style of the THIS call specification.
[2] The statement calls the destructor of the AAA.
At the end of the program, the function of the 442410H registered by the ATEXIT function will be called, and the destructor of the AAA is called. This guarantees the call of the destructor.
3. After understanding the local static object, let's take a look at the global object.
We know that the global object must have been constructed before the main function. In order to figure out when the global object is constructed, I set a breakpoint at the instantian of the global object, and the stack called:
Static.exe! AAAA :: `Dynamic Initializer '() line 22
C
Static.exe! _initterm (void) * * pfbegin = 0x00451038, void (void) * * pfend = 0x00451064) Line 707
C
Static.exe! _Cinit (int initfloatingprecision = 1) line 208 0xf bytes
C
Static.exe! maincrtstartup () line 266 0x7 Bytes
C
As a contrast, I set out breakpoints in the destructor of AAA, and the stack called:
Static.exe! AAA :: ~ AAA () Line 19
C
Static.exe! AAAA :: `Dynamic Atexit Destructor '() 0x28 Bytes
C
Static.exe! doexit (int code = 0, int Quick = 0, int Retcaller = 0) line 451
C
Static.exe! EXIT (int code = 0) Line 311 0xD bytes
C
Static.exe! maincrtstartup () line 289
C
Thus we can see that the actual entry point of the program is mainly transcribed instead of the main function (in terms of console program relative to ANSI).
Let's analyze _cinit function:
In the comment, there is a sentence [3. General C Initializer Routines]. It seems that one of the functions of this function is to complete the initialization routine of C.
The core code of the function is as follows:
/ *
* Do INITIALIZATIONS
* /
Initret = _initterm_e (__XI_A, __XI_Z);
/ *
* DO C Initializations
* /
_initterm (__XC_A, __XC_Z);
It seems that this function is primarily C, C initialization. We further analyze the function _initterm_e and _initterm, the function of the two functions is the same, all traversal function pointer (starting position [__XI_A, __ xi_z], end position [__XC_A, __ XC_Z]), if the function The pointer is not NULL, then the function is called.
So __Xi_a, __ xi_z and __xc_a, what is __ xc_z? There is the following code in the cinitexe.c file: #pragma data_seg (". CRT $ xia")
_CRTalloc (". CRT $ xia") _PVFV __XI_A [] = {null};
#pragma data_seg (". CRT $ xiz")
_CRTalloc (". CRT $ xiz") _PVFV __XI_Z [] = {null}; / * c initializers * /
#pragma data_seg (". CRT $ XCA")
_CRTalloc (". CRT $ XCA") _PVFV __XC_A [] = {null};
#pragma data_seg (". CRT $ XCZ")
_CRTalloc (". CRT $ XCZ") _PVFV __XC_Z [] = {null}; / * C Initializers * /
#pragma comment (Linker, "/merge:.crt=.data")
It can be seen that the four variables are in the data segment. CRT $ xia, .crt $ xiz, .crt $ xca, .crt $ xcz. When the connector layout code, it is arranged in accordance with the rules of the letter according to the name according to the name. This appears in paragraph. CRT $ xiz all variables in segment. CRT $ XIA, thereby forming a linked list. For .CRT $ XCA, .CRT $ XCZ data segment. Finally, the four data segments are merged into the .data data segment.
Take a look at the type of these variables, typedef void (__cdecl * _pvfv) (void); so these variables consist of 2 initialization function pointer chain tables.
During the debugging process, see __xc_a, __ xc_z linked list, the point to the initialization function is a constructor, such as:
Static std :: _ init_locks initlocks;
Static filebuf fout (_CPP_STDOUT);
Extern_CRTData2 Ostream Cout;
The COUT object is also constructed at this time.
The call to the destructuring function is also used in the same way, but at this time, each initialization has a termination function and corresponding.
4, summary
l Compile and connect the program, the compiler puts all global object's initialization functions in. CRT $ XX, the connector merges all the .CRT $ XCX segment into the .rdata data segment. The data of the .CRT $ XCA to all segments of .CRT $ XCZ, the data composition of the initialization function pointer list.
l When executed, _initterm (__xc_a, __xc_z) function calls all initialization functions. Construct global objects. The structure object is completed, call the ATEXIT function to ensure the call of the destructor. Modern C Design is to determine the sequential order of the object by controlling the ATExit function.
l Using ATEXIT for static objects to ensure the call of the destructive function.
l At the end of the program, call EXIT to destructure global objects or static objects.