本文主要主要研究C++中数组,结构以及类的反汇编。
1.数组
数组在内存中式一块连续的区域。比如当声明char ch[100]的时候, 我们知道栈是向下增长的, 所以我们开辟地址空间的时候起地址就为[esp(esp会赋值给ebp) – 100, esp].我们可以看下如下的列子:
1 char buf[100]; 2 for (int i = 0; i < 100; i++) 3 buf[i] = i;
我们看下他的反汇编代码:
1 char buf[100]; 2 for (int i = 0; i < 100; i++) 3 00BD13A8 mov dword ptr [i],0 4 00BD13AF jmp wmain+3Ah (0BD13BAh) 5 00BD13B1 mov eax,dword ptr [i] 6 00BD13B4 add eax,1 7 00BD13B7 mov dword ptr [i],eax 8 00BD13BA cmp dword ptr [i],64h 9 00BD13BE jge wmain+4Ch (0BD13CCh) //到这里是一个典型的for循环标志了 10 buf[i] = i; 11 00BD13C0 mov eax,dword ptr [i] //把当前i的值赋予eax,这个eax是用来计算内存位置的 12 00BD13C3 mov cl,byte ptr [i] // 因为是char型,所以复制给cl, 这个是给内存赋值的 13 00BD13C6 mov byte ptr [ebp+eax-6Ch],cl //计算当前buf[i]在栈中的位置,并赋值 14 00BD13CA jmp wmain+31h (0BD13B1h)
从上面我们就可以知道buf[0] = [ebp-100]; buf[1] = [ebp -99]……
2.结构体
我们声明这样一个结构体
1 struct myStruct 2 { 3 int a; 4 char b; 5 float c; 6 };
然后调用之:
1 int _tmain(int argc, _TCHAR* argv[]) 2 { 3 int n = sizeof(myStruct); 4 n = sizeof(float); 5 myStruct test; 6 test.a = 0; 7 test.b = 'a'; 8 test.c = 1.0f; 9 return 0; 10 }
我们看下其内存是如何分布的:
1 int n = sizeof(myStruct); 2 00FB13A8 mov dword ptr [ebp-0Ch],0Ch 3 n = sizeof(float); 4 00FB13AF mov dword ptr [ebp-0Ch],4 5 myStruct test; 6 test.a = 0; 7 00FB13B6 mov dword ptr [ebp-20h],0 8 test.b = 'a'; 9 00FB13BD mov byte ptr [ebp-1Ch],61h 10 test.c = 1.0f; 11 00FB13C1 fld1 12 00FB13C3 fstp dword ptr [ebp-18h]
我们可以看出这个结构体的大小为OCH(12), float的大小为4, int为4, char为1, 考虑到内存对齐, 大小就得为4的整数倍, 所以为12。
test.a 在内存中的位置为[ebp-20h];
test.b 在内存中的位置为[ebp-2Ch];
test.C 在内存中的位置为[ebp-28h];
3. 类
C++中的类与结构体没有本质上的区别。都是在某一内存地址上开辟地址空间,存放和操作成员变量。我们可以看下如下的测试代码:
1 class myClass 2 { 3 private: 4 int m_a; 5 char m_b; 6 float m_c; 7 public: 8 myClass(){} 9 ~myClass(){}10 void SetA(int a) 11 { 12 m_a = a; 13 } 14 virtual void SetB(char b) 15 { 16 m_b = b; 17 } 18 virtual void SetC(float c) 19 { 20 m_c = c; 21 } 22 };
看下其反汇编的实现:
1 int n = sizeof(myClass); 2 0030144D mov dword ptr [ebp-14h],10h 3 myClass test; 4 00301454 lea ecx,[ebp-2Ch] 5 00301457 call myClass::myClass (301028h) 6 0030145C mov dword ptr [ebp-4],0 7 test.SetA(10); 8 00301463 push 0Ah 9 00301465 lea ecx,[ebp-2Ch] 10 00301468 call myClass::SetA (301014h) 11 test.SetB('a'); 12 0030146D push 61h 13 0030146F lea ecx,[ebp-2Ch] 14 00301472 call myClass::SetB (3011EFh) 15 test.SetC(1.0f); 16 00301477 push ecx 17 00301478 fld1 18 0030147A fstp dword ptr [esp] 19 0030147D lea ecx,[ebp-2Ch] 20 00301480 call myClass::SetC (301104h) 21 return 0; 22 00301485 mov dword ptr [ebp-0F8h],0 23 0030148F mov dword ptr [ebp-4],0FFFFFFFFh 24 00301496 lea ecx,[ebp-2Ch] 25 00301499 call myClass::~myClass (3010BEh) 26 0030149E mov eax,dword ptr [ebp-0F8h]
这里先稍微解释下其意思:
0030144D 表明这个类的大小为16, 那位什么不是如上结构体的为12呢, 一问类中用到虚函数,所以就有一个指向虚函数列表的指针,其大小为4。
00301457 变量调用了该类的构造函数
00301468 调用了SetA
00301472 调用了SetB
00301499 调用了析构函数
我们分别来看下着四个函数内部的实现。
(1) 构造函数
1 00301550 mov dword ptr [ebp-8],ecx 2 00301553 mov eax,dword ptr [this] //首先我们把this指针放入eax中 3 00301556 mov dword ptr [eax],offset myClass::`vftable' (306744h) //然后把虚函数列表的地址放入[eax]中 4 0030155C mov eax,dword ptr [this]
如上,我们可以看出此类的构造函数只是简单得把虚函数列表的指针指向[this]的地址。
(2) SetA
这个函数是一个的成员函数,我们看下其是如何实现的
1 003015E3 mov eax,dword ptr [this] 2 003015E6 mov ecx,dword ptr [a] 3 003015E9 mov dword ptr [eax+4],ecx
如上,可以看出很简单,把参数a的值服务[this + 4]这块地址,而这块地址保存的是成员变量m_a的值。
(3) SetB
SetB是一个虚函数, 我们看下其实如何实现的:
1 00301633 mov eax,dword ptr [this] 2 00301636 mov cl,byte ptr [b] 3 00301639 mov byte ptr [eax+8],cl
如上可以发现,虚函数的内部实现和普通的函数没有区别, 唯一不同的是虚函数的位置是放在一个类的虚函数列表里面的。
(4) 析构函数
最后我们看下此类的析构函数是怎么实现的
1 003015A0 mov dword ptr [ebp-8],ecx 2 003015A3 mov eax,dword ptr [this] 3 003015A6 mov dword ptr [eax],offset myClass::`vftable' (306744h)
因为我们在析构函数中什么事情也没有干,所以此析构函数只是简单的吧虚函数列表的地址放到[this]中。
这里我总结下声明一个类其内存是如何分配的:
当写下myStruct test;的时候会在栈上开辟一个内存空间,其地址为[this]
如果此类有虚函数,就有有一个指向此类虚函数列表的指针,其地址为[this ]
m_a 的地址为[this +4]
m_b 的地址为[this + 8]
m_c 的地址为[this + 0Ch]
原文链接: https://www.cnblogs.com/sld666666/archive/2010/10/24/1859819.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/16509
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!