As every one knows, static
variables are initialized only once, even though it is declared in a function. In this post, I will explain how the compiler implements this.
OK, let's start with the storage of the static
variables. Where do you think a static
variable declared inside a function is stored? If your answer is on the stack, you are wrong. All static and global variables are stored in a section called ".data
" in the EXE. For example, check the below code:
int g_GlobalVariable = 0x10;
static int nValue1 = 0x11;
void main()
{
static int nValue2 = 0x12;
int *pglobal = &g_GlobalVariable;
int *pValue1 = &nValue1;
int *pValue2 = &nValue2;
}
When executed, the values of pglobal
, pValue1
and pValue2
were 0x408020
, 0x408024
and 0x408028
respectively. Which means, all the three variables were stored in three consecutive locations. In the PE view, we can see these variables stored in the ".data
" section.
You can see that the "nValue2
" variable is initialized at the compile time itself. So no instruction is generated by the compiler for a statement like static int nValue2 = 0x12;
So, the compiler did a nice job by setting the value to variable at compile time itself. But that was a C type object. What if we declare a static
C++ object inside a function. This time, the compiler cannot initialize the variable at compile time because the constructor needs to be invoked to initialize a C++ object. Consider the below code:
class TestClass
{
public:
TestClass()
{
m_nMemeberVar = 10;
}
int m_nMemeberVar;
};
TestClass& AFunction()
{
static TestClass cppObject;
return cppObject;
}
In the above code, the AFunction()
function creates a static
object of class TestClass
and as you know, the cppObject
will be initialized only once. How does the compiler manage to do it? Well, the answer is that the compiler keeps a flag!!!, i.e., when the compiler sees a C++, static
object is declared inside a function, it will create a global byte
variable with value 0
and some additional instruction such that the constructor of the object will be called only if the value of the byte variable is 0
and it also sets the value of the byte variable as 1
. So from the next time onwards, the constructor will not be called. Below is the disassembly for the statement static TestClass cppObject
.
static TestClass cppObject;
00401E79 xor eax,eax
00401E7B mov al,[`AFunction'::`2'::$S230 (00408104)]
00401E80 and eax,1
00401E83 test eax,eax
00401E85 jne AFunction+3Dh (00401ead)
00401E87 mov cl,byte ptr [`AFunction'::`2'::$S230 (00408104)]
00401E8D or cl,1
00401E90 mov byte ptr [`AFunction'::`2'::$S230 (00408104)],cl
00401E96 mov ecx,offset theApp+0C8h (00408100)
00401E9B call TestClass::TestClass (00401ec0)