vs2008下C++对象内存布局(1)

快乐虾

http://blog.csdn.net/lights_joy/

[email protected]

本文适用于

Xp sp3

Vs2008

欢迎转载,但请保留作者信息

近日,因为调试cygwin.dll出了点状况,与C++对象的内存布局有关,故此决定先看看vs2008C++对象内存的管理。

1.1 最简单的类

写一小段简单代码:

class CTest

{

public:

int var_a;

int var_b;

int var_c;

public:

void fun1()

{

var_a = 10;

}

void fun2()

{

var_b = 20;

}

};

CTest a, *p;

int _tmain(int argc, _TCHAR* argv[])

{

a.var_a = 1;

a.var_b = 2;

a.var_c = 3;

p = &a;

p->fun1();

p->fun2();

return 0;

}

为了更直观地观察编译器的行为,把ap做为全局变量。

1.1.1 赋值语句的行为

先观察赋值语句的行为:

a.var_a = 1;

004113CE C7 05 C0 74 41 00 01 00 00 00 mov dword ptr [a (4174C0h)],1

a.var_b = 2;

004113D8 C7 05 C4 74 41 00 02 00 00 00 mov dword ptr [a+4 (4174C4h)],2

a.var_c = 3;

004113E2 C7 05 C8 74 41 00 03 00 00 00 mov dword ptr [a+8 (4174C8h)],3

再观察赋值结束后p指向的内存区域:

0x004174C0 01 00 00 00 02 00 00 00 03 00 00 00 00 00 00 ...............

显然,这个时候p指向CTest::var_a,也就是说vs2008并没有在类中插入多余的内容。CTest的大小为var_a, var_b, var_c的大小之和,即12个字节。

1.1.2 函数调用的行为

再观察一下函数调用的行为:

p->fun1();

004113F6 8B 0D BC 74 41 00 mov ecx,dword ptr [p (4174BCh)]

004113FC E8 53 FD FF FF call CTest::fun1 (411154h)

这段代码可以说明CTest::fun1的调用和其它的C代码并没有什么不同,一个函数而已。看看call把我们带到哪里:

00411118 E9 83 03 00 00 jmp CTest::fun2 (4114A0h)

0041111D E9 6E 15 00 00 jmp __CxxUnhandledExceptionFilter (412690h)

00411122 E9 E9 15 00 00 jmp __CxxSetUnhandledExceptionFilter (412710h)

00411127 E9 64 24 00 00 jmp QueryPerformanceCounter (413590h)

0041112C E9 9F 16 00 00 jmp _wsetargv (4127D0h)

00411131 E9 0A 17 00 00 jmp __p__commode (412840h)

00411136 E9 89 22 00 00 jmp _unlock (4133C4h)

0041113B E9 62 24 00 00 jmp GetCurrentProcessId (4135A2h)

00411140 E9 9B 04 00 00 jmp _RTC_CheckStackVars2 (4115E0h)

00411145 E9 80 18 00 00 jmp __set_app_type (4129CAh)

0041114A E9 A1 03 00 00 jmp _RTC_CheckEsp (4114F0h)

0041114F E9 8C 16 00 00 jmp _RTC_Initialize (4127E0h)

00411154 E9 07 03 00 00 jmp CTest::fun1 (411460h)

一个神秘的地方,只是func1func2为什么要离得这么远呢?莫非有什么特殊的考虑?暂且不管它,在jmp的带领下,看到了func1的代码:

void fun1()

{

00411460 55 push ebp

00411461 8B EC mov ebp,esp

00411463 81 EC CC 00 00 00 sub esp,0CCh

00411469 53 push ebx

0041146A 56 push esi

0041146B 57 push edi

0041146C 51 push ecx

0041146D 8D BD 34 FF FF FF lea edi,[ebp-0CCh]

00411473 B9 33 00 00 00 mov ecx,33h

00411478 B8 CC CC CC CC mov eax,0CCCCCCCCh

0041147D F3 AB rep stos dword ptr es:[edi]

0041147F 59 pop ecx

00411480 89 4D F8 mov dword ptr [ebp-8],ecx

var_a = 10;

00411483 8B 45 F8 mov eax,dword ptr [this]

00411486 C7 00 0A 00 00 00 mov dword ptr [eax],0Ah

}

0041148C 5F pop edi

0041148D 5E pop esi

0041148E 5B pop ebx

0041148F 8B E5 mov esp,ebp

00411491 5D pop ebp

00411492 C3 ret

传说中的对象应该有一个this指针的,怎么传递过来的?

在调用fun1之前,将p的值赋给了ecx,在fun1里面,其它寄存器都是函数开始就入栈,函数退出时再出栈,唯独ecx是个例外,想来vs就是通过ECX来传递this指针的值。

1.1.3 p指向自定义的缓冲区

由于在此种简单情况下,vs2008并没有添加额外的空间,想来把p指向自己定义的数组再调用其成员函数应该也可以工作得很好,试试下面的代码:

int buf[3] = {4, 5, 6};

p = (CTest*)buf;

p->fun1();

经过此调用,buf[0]的值果然变成了10

你可能感兴趣的:(C++,c,.net,C#,XP)