从汇编代码学习C++语言1—类对象构造函数与析构函数
类对象必须经历初始化与销毁两个过程,类的构造函数与析构函数担当此重任。本文作为从汇编代码学习C++语言系列的第一篇,来分析类对象如何构造与销毁。
示例代码1:
class Object
{
public:
int code1;
int code2;
};
int main(int argc, char *argv[])
{
int i = 0;
Object c;
//func(1, c, 2);
return 0;
}
示例代码1没有实现构造函数与析构函数,汇编代码如下:
Disassembly of section .text:
00000000 <_main>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 e4 f0 and $0xfffffff0,%esp //Memory Alignment
6: 83 ec 10 sub $0x10,%esp //Assign stack Memory, 16Bytes
9: e8 00 00 00 00 call e <_main+0xe>
e: c7 44 24 0c 00 00 00 movl $0x0,0xc(%esp) //Assign 0 to Memory Address(esp + 12Bytes)
15: 00
16: b8 00 00 00 00 mov $0x0,%eax //Summary: code1 and code2 is not assigned value.
1b: c9 leave
1c: c3 ret
1d: 90 nop
1e: 90 nop
1f: 90 nop
示例代码2:
class Object
{
public:
Object(){}
~Object(){}
int code1;
int code2;
};
int main(int argc, char *argv[])
{
int i = 0;
Object c;
//func(1, c, 2);
return 0;
}
示例代码2实现构造函数与析构函数,汇编代码如下:
Disassembly of section .text:
00000000 <_main>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 53 push %ebx
4: 83 e4 f0 and $0xfffffff0,%esp
7: 83 ec 20 sub $0x20,%esp //Assign Stack Memory,32Bytes
a: e8 00 00 00 00 call f <_main+0xf>
f: c7 44 24 1c 00 00 00 movl $0x0,0x1c(%esp) //Assign Zero to Memory Address(esp + 28Bytes)
16: 00
17: 8d 44 24 14 lea 0x14(%esp),%eax //Assign Memory Address(esp + 20Bytes) to eax
1b: 89 04 24 mov %eax,(%esp) //Assign eax to esp, so now esp will point to esp + 20Bytes
1e: e8 00 00 00 00 call 23 <_main+0x23> //Call Object constructor function (ObjectC1Ev)
23: bb 00 00 00 00 mov $0x0,%ebx
28: 8d 44 24 14 lea 0x14(%esp),%eax //Assign Memory Address(esp + 20Bytes) to eax
2c: 89 04 24 mov %eax,(%esp) //Move eax to esp
2f: e8 00 00 00 00 call 34 <_main+0x34> //Call Object destructor function (ObjectD1Ev)
34: 89 d8 mov %ebx,%eax
36: 8b 5d fc mov -0x4(%ebp),%ebx //
39: c9 leave
3a: c3 ret
3b: 90 nop
Disassembly of section .text$_ZN6ObjectC1Ev:
00000000 <__ZN6ObjectC1Ev>: //do nothing, just do stack balance
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 5d pop %ebp
4: c3 ret
5: 90 nop
6: 90 nop
7: 90 nop
Disassembly of section .text$_ZN6ObjectD1Ev:
00000000 <__ZN6ObjectD1Ev>: //do nothing, just do stack balance
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 5d pop %ebp
4: c3 ret
5: 90 nop
6: 90 nop
7: 90 nop
Sample Code 3, let constructor and destructor do something:
class Object
{
public:
Object()
{
code1 = 10;
code2 = 5;
}
~Object()
{
code1 = 0;
code2 = 0;
}
int code1;
int code2;
};
int main(int argc, char *argv[])
{
int i = 0;
Object c;
//func(1, c, 2);
return 0;
}
And assembly codes list following:
Disassembly of section .text:
00000000 <_main>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 53 push %ebx
4: 83 e4 f0 and $0xfffffff0,%esp // see above
7: 83 ec 20 sub $0x20,%esp
a: e8 00 00 00 00 call f <_main+0xf>
f: c7 44 24 1c 00 00 00 movl $0x0,0x1c(%esp)
16: 00
17: 8d 44 24 14 lea 0x14(%esp),%eax
1b: 89 04 24 mov %eax,(%esp)
1e: e8 00 00 00 00 call 23 <_main+0x23>
23: bb 00 00 00 00 mov $0x0,%ebx
28: 8d 44 24 14 lea 0x14(%esp),%eax
2c: 89 04 24 mov %eax,(%esp)
2f: e8 00 00 00 00 call 34 <_main+0x34>
34: 89 d8 mov %ebx,%eax
36: 8b 5d fc mov -0x4(%ebp),%ebx
39: c9 leave
3a: c3 ret
3b: 90 nop
Disassembly of section .text$_ZN6ObjectC1Ev:
00000000 <__ZN6ObjectC1Ev>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 8b 45 08 mov 0x8(%ebp),%eax //
6: c7 00 0a 00 00 00 movl $0xa,(%eax) //Assign 10 to ebp + 8
c: 8b 45 08 mov 0x8(%ebp),%eax
f: c7 40 04 0a 00 00 00 movl $0x5,0x4(%eax) //Assign 5 to (ebp + 8) + 4,
//note stack memory assigns from high to low.
//So ebp+8 is address of Object c.
16: 5d pop %ebp
17: c3 ret
Disassembly of section .text$_ZN6ObjectD1Ev:
00000000 <__ZN6ObjectD1Ev>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 8b 45 08 mov 0x8(%ebp),%eax
6: c7 00 00 00 00 00 movl $0x0,(%eax)
c: 8b 45 08 mov 0x8(%ebp),%eax
f: c7 40 04 00 00 00 00 movl $0x0,0x4(%eax)
16: 5d pop %ebp
17: c3 ret