-
-
[原创]从逆向工程的角度来看C++ (六)
-
发表于: 2009-5-1 12:21 4490
-
进入本次正题:
(六)[ C++ 之 命名控制 ]
static int i; 这种静态变量是在.data段中的.
我们来看下在类中使用静态成员.
// Lesson6.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream.h>
#include <windows.h>
class X
{
int i;
public:
X(int I = 0):i(I){cout << "X::X()"<< endl;} //
~X(){cout << "X::~X()"<< endl;exit(1);cout << "X::~X()"<< endl;}
friend void f();
};
void f()
{
static X x1(47);
cout<<&x1<<"-"<<sizeof(x1)<<"-"<<x1.i<<endl;
}
int main(int argc, char* argv[])
{
// __asm int 3
f();
return 0;
}
函数f中定义了一个静态的对象. 对于静态对象:
1.程序控制第一次转到对象的定义点时, 而且只有在第一次时, 才需要执行构造函数.
2.静态对象的析构函数(包括静态存储的所有对象,不仅仅是上例中的局部静态变量)在程序从main() 块中退出时,或者标准的C库函数e x i t ( )被调用时才被调用, 实验证明析构函数调用发生在exit 栈帧中,_exit栈帧外.
实验说明:
当析构为:~X(){cout << "X::~X()"<< endl;}时: 输出为:
X::X()
0x0042E060-4-47
X::~X()
当析构为~X(){cout << "X::~X()"<< endl;_exit(1);}时,输出为:
X::X()
0x0042E060-4-47
X::~X()
当析构为~X(){cout << "X::~X()"<< endl;exit(1);}时,输出为:
X::X()
0x0042E060-4-47
X::~X()
X::~X()
X::~X()
X::~X()
... ...
发生了嵌套调用了.
//再来看看这个CPP:
// Lesson6.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream.h>
int x = 100;
class X
{
static int i;
static int j;
public:
void X::prt() const
{
i *=100;
j *=100;
cout << "i = " << i <<endl;
cout << "j = " << j <<endl;
}
static void X::f()
{
cout << "sum = " << i+j <<endl;
}
};
int X::i = 9;
int X::j = x + 1;
int main(int argc, char* argv[])
{
__asm int 3
X x;
cout << "sizeof X = "<< sizeof(x) <<endl ;
x.prt();
X::f();
return 0;
}
//Dasm:
004010C0 > 55 push ebp
004010C1 8BEC mov ebp,esp
004010C3 83EC 44 sub esp,44
004010C6 53 push ebx
004010C7 56 push esi
004010C8 57 push edi
004010C9 8D7D BC lea edi,dword ptr ss:[ebp-44]
004010CC B9 11000000 mov ecx,11
004010D1 B8 CCCCCCCC mov eax,CCCCCCCC
004010D6 F3:AB rep stos dword ptr es:[edi]
004010D8 90 nop
004010D9 68 0F104000 push Lesson6.0040100F ; endl
004010DE 6A 01 push 1 ; sizeof(X)
004010E0 68 F0904200 push Lesson6.004290F0 ; ASCII "sizeof X = "
004010E5 B9 68E34200 mov ecx,offset Lesson6.cout
004010EA E8 11C80000 call Lesson6.ostream::operator<<
004010EF 8BC8 mov ecx,eax
004010F1 E8 EA050100 call Lesson6.ostream::operator<<
004010F6 8BC8 mov ecx,eax
004010F8 E8 08FFFFFF call Lesson6.00401005
004010FD 8D4D FC lea ecx,dword ptr ss:[ebp-4] ; 传this
00401100 E8 0FFFFFFF call Lesson6.00401014 ; 非静态方法 X::prt()
00401105 E8 19FFFFFF call Lesson6.00401023 ; 静态方法X::f()
0040110A 33C0 xor eax,eax ; Lesson6.cout
0040110C 5F pop edi
0040110D 5E pop esi
0040110E 5B pop ebx
0040110F 83C4 44 add esp,44
00401112 3BEC cmp ebp,esp
00401114 E8 E7010000 call Lesson6._chkesp
00401119 8BE5 mov esp,ebp
0040111B 5D pop ebp
0040111C C3 retn
////Release
00401020 90 nop
00401021 6A 01 push 1 ; sizeof(x)
00401023 68 70904000 push Lesson6.00409070 ; ASCII "sizeof X = "
00401028 B9 98BB4000 mov ecx,Lesson6.0040BB98 ; cout
0040102D E8 493C0000 call Lesson6.00404C7B ; <<
00401032 8BC8 mov ecx,eax
00401034 E8 EE3A0000 call Lesson6.00404B27 ; <<
00401039 68 30114000 push Lesson6.00401130
0040103E 6A 0A push 0A
00401040 8BC8 mov ecx,eax
00401042 E8 423A0000 call Lesson6.00404A89
00401047 8BC8 mov ecx,eax
00401049 E8 C2000000 call Lesson6.00401110
0040104E A1 54904000 mov eax,dword ptr ds:[409054] ; 成员变量 i 赤裸于此
00401053 8B0D E0B94000 mov ecx,dword ptr ds:[40B9E0] ; 成员变量 j 赤裸于此
00401059 8D0480 lea eax,dword ptr ds:[eax+eax*4] ; i *=5
0040105C 8D0C89 lea ecx,dword ptr ds:[ecx+ecx*4]
0040105F 8D0480 lea eax,dword ptr ds:[eax+eax*4] ; i *= 5
00401062 8D0C89 lea ecx,dword ptr ds:[ecx+ecx*4]
00401065 C1E0 02 shl eax,2 ; * 4
00401068 C1E1 02 shl ecx,2
0040106B 890D E0B94000 mov dword ptr ds:[40B9E0],ecx ; 写回 静态的 j
00401071 50 push eax
00401072 68 68904000 push Lesson6.00409068 ; ASCII "i = "
00401077 B9 98BB4000 mov ecx,Lesson6.0040BB98 ; cout 地址,ecx传参
0040107C A3 54904000 mov dword ptr ds:[409054],eax ; 写回 静态的 i
00401081 E8 F53B0000 call Lesson6.00404C7B ; <<
00401086 8BC8 mov ecx,eax
00401088 E8 4B390000 call Lesson6.004049D8 ; <<
0040108D 68 30114000 push Lesson6.00401130
00401092 6A 0A push 0A
00401094 8BC8 mov ecx,eax ; <<
00401096 E8 EE390000 call Lesson6.00404A89
0040109B 8BC8 mov ecx,eax
0040109D E8 6E000000 call Lesson6.00401110
004010A2 8B15 E0B94000 mov edx,dword ptr ds:[40B9E0] ; j
004010A8 B9 98BB4000 mov ecx,Lesson6.0040BB98
004010AD 52 push edx
004010AE 68 60904000 push Lesson6.00409060 ; ASCII "j = "
004010B3 E8 C33B0000 call Lesson6.00404C7B ; <<
004010B8 8BC8 mov ecx,eax
004010BA E8 19390000 call Lesson6.004049D8 ; <<
004010BF 68 30114000 push Lesson6.00401130
004010C4 6A 0A push 0A
004010C6 8BC8 mov ecx,eax
004010C8 E8 BC390000 call Lesson6.00404A89
004010CD 8BC8 mov ecx,eax
004010CF E8 3C000000 call Lesson6.00401110
004010D4 A1 54904000 mov eax,dword ptr ds:[409054]
004010D9 8B0D E0B94000 mov ecx,dword ptr ds:[40B9E0]
004010DF 03C8 add ecx,eax
004010E1 51 push ecx
004010E2 68 58904000 push Lesson6.00409058 ; ASCII "sum = "
004010E7 B9 98BB4000 mov ecx,Lesson6.0040BB98 ; cout
004010EC E8 8A3B0000 call Lesson6.00404C7B ; <<
004010F1 8BC8 mov ecx,eax
004010F3 E8 E0380000 call Lesson6.004049D8
004010F8 68 30114000 push Lesson6.00401130
004010FD 6A 0A push 0A
004010FF 8BC8 mov ecx,eax
00401101 E8 83390000 call Lesson6.00404A89
00401106 8BC8 mov ecx,eax
00401108 E8 03000000 call Lesson6.00401110
0040110D 33C0 xor eax,eax ; Lesson6.0040BB98
0040110F C3 retn
小结:Release版本的优化了不少, 看的出来, Release合并了一些简单的成员函数.
另: 静态方法直接call全局地址. 跟普通方法没区别;
还有sizeof(X) 的值为1 , 象征性的1. X x 该局部变量也就一个DWORD. 而且还是cccccccc填充, 根本没用这个值.
面向对象始终还是为编译器服务的.静态成员都是赤裸裸的.data段数据调用类静态方法也是不需要传this指针 .
到了这里,静态嵌套类也不用做实验了, 理解了思想, 就理解了一切, 什么东西都是一样的 .
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!