C++对象构造和析构

//遗留的问题:C++中构造函数和析构函数的执行顺序到底是怎么样的呢?class Object{private:    int val;public:    Object(int x)    {        val = x;        cout << "create :" << val << endl;    }    };Object o1(1);int main(){    Object o2(2);}Object o3(3);

代码在Linux64平台编译运行,objdump -d 生成反汇编代码

汇编代码如下:

反汇编代码
Object:     文件格式 elf64-x86-64Disassembly of section .init:0000000000001000 :    1000:       f3 0f 1e fa             endbr64     1004:       48 83 ec 08             sub    $0x8,%rsp    1008:       48 8b 05 d9 2f 00 00    mov    0x2fd9(%rip),%rax        # 3fe8     100f:       48 85 c0                test   %rax,%rax    1012:       74 02                   je     1016     1014:       ff d0                   callq  *%rax    1016:       48 83 c4 08             add    $0x8,%rsp    101a:       c3                      retq   Disassembly of section .plt:0000000000001020 :    1020:       ff 35 62 2f 00 00       pushq  0x2f62(%rip)        # 3f88     1026:       f2 ff 25 63 2f 00 00    bnd jmpq *0x2f63(%rip)        # 3f90     102d:       0f 1f 00                nopl   (%rax)    1030:       f3 0f 1e fa             endbr64     1034:       68 00 00 00 00          pushq  $0x0    1039:       f2 e9 e1 ff ff ff       bnd jmpq 1020     103f:       90                      nop    1040:       f3 0f 1e fa             endbr64     1044:       68 01 00 00 00          pushq  $0x1    1049:       f2 e9 d1 ff ff ff       bnd jmpq 1020     104f:       90                      nop    1050:       f3 0f 1e fa             endbr64     1054:       68 02 00 00 00          pushq  $0x2    1059:       f2 e9 c1 ff ff ff       bnd jmpq 1020     105f:       90                      nop    1060:       f3 0f 1e fa             endbr64     1064:       68 03 00 00 00          pushq  $0x3    1069:       f2 e9 b1 ff ff ff       bnd jmpq 1020     106f:       90                      nop    1070:       f3 0f 1e fa             endbr64     1074:       68 04 00 00 00          pushq  $0x4    1079:       f2 e9 a1 ff ff ff       bnd jmpq 1020     107f:       90                      nop    1080:       f3 0f 1e fa             endbr64     1084:       68 05 00 00 00          pushq  $0x5    1089:       f2 e9 91 ff ff ff       bnd jmpq 1020     108f:       90                      nopDisassembly of section .plt.got:0000000000001090 :    1090:       f3 0f 1e fa             endbr64     1094:       f2 ff 25 2d 2f 00 00    bnd jmpq *0x2f2d(%rip)        # 3fc8     109b:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)Disassembly of section .plt.sec:00000000000010a0 :    10a0:       f3 0f 1e fa             endbr64     10a4:       f2 ff 25 ed 2e 00 00    bnd jmpq *0x2eed(%rip)        # 3f98     10ab:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)00000000000010b0 :    10b0:       f3 0f 1e fa             endbr64     10b4:       f2 ff 25 e5 2e 00 00    bnd jmpq *0x2ee5(%rip)        # 3fa0     10bb:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)00000000000010c0 :    10c0:       f3 0f 1e fa             endbr64     10c4:       f2 ff 25 dd 2e 00 00    bnd jmpq *0x2edd(%rip)        # 3fa8     10cb:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)00000000000010d0 :    10d0:       f3 0f 1e fa             endbr64     10d4:       f2 ff 25 d5 2e 00 00    bnd jmpq *0x2ed5(%rip)        # 3fb0     10db:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)00000000000010e0 :    10e0:       f3 0f 1e fa             endbr64     10e4:       f2 ff 25 cd 2e 00 00    bnd jmpq *0x2ecd(%rip)        # 3fb8     10eb:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)00000000000010f0 :    10f0:       f3 0f 1e fa             endbr64     10f4:       f2 ff 25 c5 2e 00 00    bnd jmpq *0x2ec5(%rip)        # 3fc0     10fb:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)Disassembly of section .text:0000000000001100 :    1100:       f3 0f 1e fa             endbr64     1104:       31 ed                   xor    %ebp,%ebp    1106:       49 89 d1                mov    %rdx,%r9    1109:       5e                      pop    %rsi    110a:       48 89 e2                mov    %rsp,%rdx    110d:       48 83 e4 f0             and    $0xfffffffffffffff0,%rsp    1111:       50                      push   %rax    1112:       54                      push   %rsp    1113:       4c 8d 05 f6 02 00 00    lea    0x2f6(%rip),%r8        # 1410     111a:       48 8d 0d 7f 02 00 00    lea    0x27f(%rip),%rcx        # 13a0     1121:       48 8d 3d c1 00 00 00    lea    0xc1(%rip),%rdi        # 11e9 
1128: ff 15 b2 2e 00 00 callq *0x2eb2(%rip) # 3fe0 112e: f4 hlt 112f: 90 nop0000000000001130 : 1130: 48 8d 3d e1 2e 00 00 lea 0x2ee1(%rip),%rdi # 4018 1137: 48 8d 05 da 2e 00 00 lea 0x2eda(%rip),%rax # 4018 113e: 48 39 f8 cmp %rdi,%rax 1141: 74 15 je 1158 1143: 48 8b 05 8e 2e 00 00 mov 0x2e8e(%rip),%rax # 3fd8 114a: 48 85 c0 test %rax,%rax 114d: 74 09 je 1158 114f: ff e0 jmpq *%rax 1151: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 1158: c3 retq 1159: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)0000000000001160 : 1160: 48 8d 3d b1 2e 00 00 lea 0x2eb1(%rip),%rdi # 4018 1167: 48 8d 35 aa 2e 00 00 lea 0x2eaa(%rip),%rsi # 4018 116e: 48 29 fe sub %rdi,%rsi 1171: 48 89 f0 mov %rsi,%rax 1174: 48 c1 ee 3f shr $0x3f,%rsi 1178: 48 c1 f8 03 sar $0x3,%rax 117c: 48 01 c6 add %rax,%rsi 117f: 48 d1 fe sar %rsi 1182: 74 14 je 1198 1184: 48 8b 05 65 2e 00 00 mov 0x2e65(%rip),%rax # 3ff0 118b: 48 85 c0 test %rax,%rax 118e: 74 08 je 1198 1190: ff e0 jmpq *%rax 1192: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) 1198: c3 retq 1199: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)00000000000011a0 : 11a0: f3 0f 1e fa endbr64 11a4: 80 3d a5 2f 00 00 00 cmpb $0x0,0x2fa5(%rip) # 4150 11ab: 75 2b jne 11d8 11ad: 55 push %rbp 11ae: 48 83 3d 12 2e 00 00 cmpq $0x0,0x2e12(%rip) # 3fc8 11b5: 00 11b6: 48 89 e5 mov %rsp,%rbp 11b9: 74 0c je 11c7 11bb: 48 8b 3d 46 2e 00 00 mov 0x2e46(%rip),%rdi # 4008 11c2: e8 c9 fe ff ff callq 1090 11c7: e8 64 ff ff ff callq 1130 11cc: c6 05 7d 2f 00 00 01 movb $0x1,0x2f7d(%rip) # 4150 11d3: 5d pop %rbp 11d4: c3 retq 11d5: 0f 1f 00 nopl (%rax) 11d8: c3 retq 11d9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)00000000000011e0 : 11e0: f3 0f 1e fa endbr64 11e4: e9 77 ff ff ff jmpq 1160 00000000000011e9
: 11e9: f3 0f 1e fa endbr64 11ed: 55 push %rbp 11ee: 48 89 e5 mov %rsp,%rbp 11f1: 48 83 ec 10 sub $0x10,%rsp 11f5: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax 11fc: 00 00 11fe: 48 89 45 f8 mov %rax,-0x8(%rbp) 1202: 31 c0 xor %eax,%eax 1204: 48 8d 45 f4 lea -0xc(%rbp),%rax 1208: be 02 00 00 00 mov $0x2,%esi 120d: 48 89 c7 mov %rax,%rdi 1210: e8 e7 00 00 00 callq 12fc 1215: 48 8d 45 f4 lea -0xc(%rbp),%rax 1219: 48 89 c7 mov %rax,%rdi 121c: e8 35 01 00 00 callq 1356 1221: b8 00 00 00 00 mov $0x0,%eax 1226: 48 8b 55 f8 mov -0x8(%rbp),%rdx 122a: 64 48 33 14 25 28 00 xor %fs:0x28,%rdx 1231: 00 00 1233: 74 05 je 123a
1235: e8 96 fe ff ff callq 10d0 123a: c9 leaveq 123b: c3 retq 000000000000123c : 123c: f3 0f 1e fa endbr64 1240: 55 push %rbp 1241: 48 89 e5 mov %rsp,%rbp 1244: 48 83 ec 10 sub $0x10,%rsp 1248: 89 7d fc mov %edi,-0x4(%rbp) 124b: 89 75 f8 mov %esi,-0x8(%rbp) 124e: 83 7d fc 01 cmpl $0x1,-0x4(%rbp) 1252: 0f 85 88 00 00 00 jne 12e0 1258: 81 7d f8 ff ff 00 00 cmpl $0xffff,-0x8(%rbp) 125f: 75 7f jne 12e0 1261: 48 8d 3d f4 2e 00 00 lea 0x2ef4(%rip),%rdi # 415c 1268: e8 73 fe ff ff callq 10e0 126d: 48 8d 15 94 2d 00 00 lea 0x2d94(%rip),%rdx # 4008 1274: 48 8d 35 e1 2e 00 00 lea 0x2ee1(%rip),%rsi # 415c 127b: 48 8b 05 76 2d 00 00 mov 0x2d76(%rip),%rax # 3ff8 1282: 48 89 c7 mov %rax,%rdi 1285: e8 16 fe ff ff callq 10a0 128a: be 01 00 00 00 mov $0x1,%esi 128f: 48 8d 3d be 2e 00 00 lea 0x2ebe(%rip),%rdi # 4154 1296: e8 61 00 00 00 callq 12fc 129b: 48 8d 15 66 2d 00 00 lea 0x2d66(%rip),%rdx # 4008 12a2: 48 8d 35 ab 2e 00 00 lea 0x2eab(%rip),%rsi # 4154 12a9: 48 8d 3d a6 00 00 00 lea 0xa6(%rip),%rdi # 1356 12b0: e8 eb fd ff ff callq 10a0 12b5: be 03 00 00 00 mov $0x3,%esi 12ba: 48 8d 3d 97 2e 00 00 lea 0x2e97(%rip),%rdi # 4158 12c1: e8 36 00 00 00 callq 12fc 12c6: 48 8d 15 3b 2d 00 00 lea 0x2d3b(%rip),%rdx # 4008 12cd: 48 8d 35 84 2e 00 00 lea 0x2e84(%rip),%rsi # 4158 12d4: 48 8d 3d 7b 00 00 00 lea 0x7b(%rip),%rdi # 1356 12db: e8 c0 fd ff ff callq 10a0 12e0: 90 nop 12e1: c9 leaveq 12e2: c3 retq 00000000000012e3 : 12e3: f3 0f 1e fa endbr64 12e7: 55 push %rbp 12e8: 48 89 e5 mov %rsp,%rbp 12eb: be ff ff 00 00 mov $0xffff,%esi 12f0: bf 01 00 00 00 mov $0x1,%edi 12f5: e8 42 ff ff ff callq 123c 12fa: 5d pop %rbp 12fb: c3 retq 00000000000012fc : 12fc: f3 0f 1e fa endbr64 1300: 55 push %rbp 1301: 48 89 e5 mov %rsp,%rbp 1304: 48 83 ec 10 sub $0x10,%rsp 1308: 48 89 7d f8 mov %rdi,-0x8(%rbp) 130c: 89 75 f4 mov %esi,-0xc(%rbp) 130f: 48 8b 45 f8 mov -0x8(%rbp),%rax 1313: 8b 55 f4 mov -0xc(%rbp),%edx 1316: 89 10 mov %edx,(%rax) 1318: 48 8d 35 e6 0c 00 00 lea 0xce6(%rip),%rsi # 2005 131f: 48 8d 3d 1a 2d 00 00 lea 0x2d1a(%rip),%rdi # 4040 1326: e8 85 fd ff ff callq 10b0 132b: 48 89 c2 mov %rax,%rdx 132e: 48 8b 45 f8 mov -0x8(%rbp),%rax 1332: 8b 00 mov (%rax),%eax 1334: 89 c6 mov %eax,%esi 1336: 48 89 d7 mov %rdx,%rdi 1339: e8 b2 fd ff ff callq 10f0 133e: 48 89 c2 mov %rax,%rdx 1341: 48 8b 05 88 2c 00 00 mov 0x2c88(%rip),%rax # 3fd0 1348: 48 89 c6 mov %rax,%rsi 134b: 48 89 d7 mov %rdx,%rdi 134e: e8 6d fd ff ff callq 10c0 1353: 90 nop 1354: c9 leaveq 1355: c3 retq 0000000000001356 : 1356: f3 0f 1e fa endbr64 135a: 55 push %rbp 135b: 48 89 e5 mov %rsp,%rbp 135e: 48 83 ec 10 sub $0x10,%rsp 1362: 48 89 7d f8 mov %rdi,-0x8(%rbp) 1366: 48 8d 35 a1 0c 00 00 lea 0xca1(%rip),%rsi # 200e 136d: 48 8d 3d cc 2c 00 00 lea 0x2ccc(%rip),%rdi # 4040 1374: e8 37 fd ff ff callq 10b0 1379: 48 89 c2 mov %rax,%rdx 137c: 48 8b 05 4d 2c 00 00 mov 0x2c4d(%rip),%rax # 3fd0 1383: 48 89 c6 mov %rax,%rsi 1386: 48 89 d7 mov %rdx,%rdi 1389: e8 32 fd ff ff callq 10c0 138e: 90 nop 138f: c9 leaveq 1390: c3 retq 1391: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 1398: 00 00 00 139b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)00000000000013a0 : 13a0: f3 0f 1e fa endbr64 13a4: 41 57 push %r15 13a6: 4c 8d 3d bb 29 00 00 lea 0x29bb(%rip),%r15 # 3d68 13ad: 41 56 push %r14 13af: 49 89 d6 mov %rdx,%r14 13b2: 41 55 push %r13 13b4: 49 89 f5 mov %rsi,%r13 13b7: 41 54 push %r12 13b9: 41 89 fc mov %edi,%r12d 13bc: 55 push %rbp 13bd: 48 8d 2d b4 29 00 00 lea 0x29b4(%rip),%rbp # 3d78 13c4: 53 push %rbx 13c5: 4c 29 fd sub %r15,%rbp 13c8: 48 83 ec 08 sub $0x8,%rsp 13cc: e8 2f fc ff ff callq 1000 13d1: 48 c1 fd 03 sar $0x3,%rbp 13d5: 74 1f je 13f6 13d7: 31 db xor %ebx,%ebx 13d9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 13e0: 4c 89 f2 mov %r14,%rdx 13e3: 4c 89 ee mov %r13,%rsi 13e6: 44 89 e7 mov %r12d,%edi 13e9: 41 ff 14 df callq *(%r15,%rbx,8) 13ed: 48 83 c3 01 add $0x1,%rbx 13f1: 48 39 dd cmp %rbx,%rbp 13f4: 75 ea jne 13e0 13f6: 48 83 c4 08 add $0x8,%rsp 13fa: 5b pop %rbx 13fb: 5d pop %rbp 13fc: 41 5c pop %r12 13fe: 41 5d pop %r13 1400: 41 5e pop %r14 1402: 41 5f pop %r15 1404: c3 retq 1405: 66 66 2e 0f 1f 84 00 data16 nopw %cs:0x0(%rax,%rax,1) 140c: 00 00 00 00 0000000000001410 : 1410: f3 0f 1e fa endbr64 1414: c3 retq Disassembly of section .fini:0000000000001418 : 1418: f3 0f 1e fa endbr64 141c: 48 83 ec 08 sub $0x8,%rsp 1420: 48 83 c4 08 add $0x8,%rsp 1424: c3 retq

局部对象的构造和析构

首先我们找到main函数的反汇编代码:

00000000000011e9 
: 11e9: f3 0f 1e fa endbr64 11ed: 55 push %rbp 11ee: 48 89 e5 mov %rsp,%rbp 11f1: 48 83 ec 10 sub $0x10,%rsp 11f5: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax 11fc: 00 00 11fe: 48 89 45 f8 mov %rax,-0x8(%rbp) 1202: 31 c0 xor %eax,%eax 1204: 48 8d 45 f4 lea -0xc(%rbp),%rax 1208: be 02 00 00 00 mov $0x2,%esi 120d: 48 89 c7 mov %rax,%rdi 1210: e8 e7 00 00 00 callq 12fc 1215: 48 8d 45 f4 lea -0xc(%rbp),%rax 1219: 48 89 c7 mov %rax,%rdi 121c: e8 35 01 00 00 callq 1356 1221: b8 00 00 00 00 mov $0x0,%eax 1226: 48 8b 55 f8 mov -0x8(%rbp),%rdx 122a: 64 48 33 14 25 28 00 xor %fs:0x28,%rdx 1231: 00 00 1233: 74 05 je 123a
1235: e8 96 fe ff ff callq 10d0 123a: c9 leaveq 123b: c3 retq

从main函数的反汇编代码中,我们可以看出,在main函数只构造了o2这一个对象,o2的构造函数被命名为 _ZN6ObjectC1Ei,析构函数被命名为 _ZN6ObjectD1Ev。

第10行,将对象的地址传递给rax寄存器。

第11行,将括号中的参数传递给寄存器esi。

第12行,将rax寄存器的地址传递给隐藏参数&obj(this指针)。

在第16行,调用析构函数,释放函数占用的资源。

构造函数:

00000000000012fc :    12fc:       f3 0f 1e fa             endbr64     1300:       55                      push   %rbp    1301:       48 89 e5                mov    %rsp,%rbp    1304:       48 83 ec 10             sub    $0x10,%rsp    1308:       48 89 7d f8             mov    %rdi,-0x8(%rbp)    130c:       89 75 f4                mov    %esi,-0xc(%rbp)    130f:       48 8b 45 f8             mov    -0x8(%rbp),%rax    1313:       8b 55 f4                mov    -0xc(%rbp),%edx    1316:       89 10                   mov    %edx,(%rax)    1318:       48 8d 35 e6 0c 00 00    lea    0xce6(%rip),%rsi        # 2005     131f:       48 8d 3d 1a 2d 00 00    lea    0x2d1a(%rip),%rdi        # 4040     1326:       e8 85 fd ff ff          callq  10b0     132b:       48 89 c2                mov    %rax,%rdx    132e:       48 8b 45 f8             mov    -0x8(%rbp),%rax    1332:       8b 00                   mov    (%rax),%eax    1334:       89 c6                   mov    %eax,%esi    1336:       48 89 d7                mov    %rdx,%rdi    1339:       e8 b2 fd ff ff          callq  10f0     133e:       48 89 c2                mov    %rax,%rdx    1341:       48 8b 05 88 2c 00 00    mov    0x2c88(%rip),%rax        # 3fd0     1348:       48 89 c6                mov    %rax,%rsi    134b:       48 89 d7                mov    %rdx,%rdi    134e:       e8 6d fd ff ff          callq  10c0     1353:       90                      nop    1354:       c9                      leaveq     1355:       c3                      retq   

析构函数:

0000000000001356 :    1356:       f3 0f 1e fa             endbr64     135a:       55                      push   %rbp    135b:       48 89 e5                mov    %rsp,%rbp    135e:       48 83 ec 10             sub    $0x10,%rsp    1362:       48 89 7d f8             mov    %rdi,-0x8(%rbp)    1366:       48 8d 35 a1 0c 00 00    lea    0xca1(%rip),%rsi        # 200e     136d:       48 8d 3d cc 2c 00 00    lea    0x2ccc(%rip),%rdi        # 4040     1374:       e8 37 fd ff ff          callq  10b0     1379:       48 89 c2                mov    %rax,%rdx    137c:       48 8b 05 4d 2c 00 00    mov    0x2c4d(%rip),%rax        # 3fd0     1383:       48 89 c6                mov    %rax,%rsi    1386:       48 89 d7                mov    %rdx,%rdi    1389:       e8 32 fd ff ff          callq  10c0     138e:       90                      nop    138f:       c9                      leaveq     1390:       c3                      retq       1391:       66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)    1398:       00 00 00     139b:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)

全局对象的构造和析构

从上述代码可以看出,局部对象o2的构造和析构在main函数中。

那么全局对象o1和o3的构造和析构在哪呢?

我们发现存在名字为<_Z41__static_initialization_and_destruction_0ii>的汇编代码:

000000000000123c :    123c:       f3 0f 1e fa             endbr64     1240:       55                      push   %rbp    1241:       48 89 e5                mov    %rsp,%rbp    1244:       48 83 ec 10             sub    $0x10,%rsp    1248:       89 7d fc                mov    %edi,-0x4(%rbp)    124b:       89 75 f8                mov    %esi,-0x8(%rbp)    124e:       83 7d fc 01             cmpl   $0x1,-0x4(%rbp)    1252:       0f 85 88 00 00 00       jne    12e0     1258:       81 7d f8 ff ff 00 00    cmpl   $0xffff,-0x8(%rbp)    125f:       75 7f                   jne    12e0     1261:       48 8d 3d f4 2e 00 00    lea    0x2ef4(%rip),%rdi        # 415c     1268:       e8 73 fe ff ff          callq  10e0     126d:       48 8d 15 94 2d 00 00    lea    0x2d94(%rip),%rdx        # 4008     1274:       48 8d 35 e1 2e 00 00    lea    0x2ee1(%rip),%rsi        # 415c     127b:       48 8b 05 76 2d 00 00    mov    0x2d76(%rip),%rax        # 3ff8     1282:       48 89 c7                mov    %rax,%rdi    1285:       e8 16 fe ff ff          callq  10a0    128a:       be 01 00 00 00          mov    $0x1,%esi    128f:       48 8d 3d be 2e 00 00    lea    0x2ebe(%rip),%rdi        # 4154     1296:       e8 61 00 00 00          callq  12fc     129b:       48 8d 15 66 2d 00 00    lea    0x2d66(%rip),%rdx        # 4008     12a2:       48 8d 35 ab 2e 00 00    lea    0x2eab(%rip),%rsi        # 4154     12a9:       48 8d 3d a6 00 00 00    lea    0xa6(%rip),%rdi        # 1356     12b0:       e8 eb fd ff ff          callq  10a0    12b5:       be 03 00 00 00          mov    $0x3,%esi    12ba:       48 8d 3d 97 2e 00 00    lea    0x2e97(%rip),%rdi        # 4158     12c1:       e8 36 00 00 00          callq  12fc     12c6:       48 8d 15 3b 2d 00 00    lea    0x2d3b(%rip),%rdx        # 4008     12cd:       48 8d 35 84 2e 00 00    lea    0x2e84(%rip),%rsi        # 4158     12d4:       48 8d 3d 7b 00 00 00    lea    0x7b(%rip),%rdi        # 1356     12db:       e8 c0 fd ff ff          callq  10a0    12e0:       90                      nop    12e1:       c9                      leaveq     12e2:       c3                      retq   

静态对象(全局对象)初始化和析构。

第21行调用构造函数,

第25行调用回调函数,

第28行调用构造函数。

在这个函数中调用了静态对象(全局对象)的构造函数,并且将其析构函数通过_cxa_atexit函数注册,使其能在exit时调用。

 00000000000012e3 :    12e3:       f3 0f 1e fa             endbr64     12e7:       55                      push   %rbp    12e8:       48 89 e5                mov    %rsp,%rbp    12eb:       be ff ff 00 00          mov    $0xffff,%esi    12f0:       bf 01 00 00 00          mov    $0x1,%edi    12f5:       e8 42 ff ff ff          callq  123c     12fa:       5d                      pop    %rbp    12fb:       c3                      retq   

_GLOBAL__sub_I_o1函数负责本编译单元所有全局\静态对象的构造和析构,那么这个函数在哪里被调用的呢?我们下面将查看程序是在哪开始执行的。

实际上在Linux环境下,glibc程序执行的入口地址是_start,这个入口是由ld链接器默认的链接脚本所指定的,当然也可以通过相关参数设定自己的入口。

程序的入口

程序入口:_start

0000000000001100 :    1100:       f3 0f 1e fa             endbr64     1104:       31 ed                   xor    %ebp,%ebp    1106:       49 89 d1                mov    %rdx,%r9    1109:       5e                      pop    %rsi    110a:       48 89 e2                mov    %rsp,%rdx    110d:       48 83 e4 f0             and    $0xfffffffffffffff0,%rsp    1111:       50                      push   %rax    1112:       54                      push   %rsp    1113:       4c 8d 05 f6 02 00 00    lea    0x2f6(%rip),%r8        # 1410     111a:       48 8d 0d 7f 02 00 00    lea    0x27f(%rip),%rcx        # 13a0     1121:       48 8d 3d c1 00 00 00    lea    0xc1(%rip),%rdi        # 11e9 
1128: ff 15 b2 2e 00 00 callq *0x2eb2(%rip) # 3fe0 112e: f4 hlt 112f: 90 nop

汇编中的注释非常清晰。

第12行才是main函数的地址。

__ libc_csu_init函数的地址是全局对象构造的地址。

__ libc_csu_fini是全局对象析构的地址。

从_ start的汇编代码可以看出,实际上_ start函数里面调用了_ libc_start_main函数,并把_libc_csu_init函数和__libc_csu_fini函数以及main函数的地址作为参数传递进去。

由于__libc_start_main函数是在glibc动态链接库里的函数,所以可执行文件的反汇编代码中并没有这一部分的代码,不过我们只需要大概了解其中先后调用关系如下:

—>_start

​—>_lib_start_main

​—>__ libc_csu_init

​—>main

​—>__libc_csu_fini

_libc_csu_init函数

00000000000013a0 :    13a0:       f3 0f 1e fa             endbr64     13a4:       41 57                   push   %r15    13a6:       4c 8d 3d bb 29 00 00    lea    0x29bb(%rip),%r15        # 3d68     13ad:       41 56                   push   %r14    13af:       49 89 d6                mov    %rdx,%r14    13b2:       41 55                   push   %r13    13b4:       49 89 f5                mov    %rsi,%r13    13b7:       41 54                   push   %r12    13b9:       41 89 fc                mov    %edi,%r12d    13bc:       55                      push   %rbp    13bd:       48 8d 2d b4 29 00 00    lea    0x29b4(%rip),%rbp        # 3d78     13c4:       53                      push   %rbx    13c5:       4c 29 fd                sub    %r15,%rbp    13c8:       48 83 ec 08             sub    $0x8,%rsp    13cc:       e8 2f fc ff ff          callq  1000     13d1:       48 c1 fd 03             sar    $0x3,%rbp    13d5:       74 1f                   je     13f6     13d7:       31 db                   xor    %ebx,%ebx    13d9:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)    13e0:       4c 89 f2                mov    %r14,%rdx    13e3:       4c 89 ee                mov    %r13,%rsi    13e6:       44 89 e7                mov    %r12d,%edi    13e9:       41 ff 14 df             callq  *(%r15,%rbx,8)    13ed:       48 83 c3 01             add    $0x1,%rbx    13f1:       48 39 dd                cmp    %rbx,%rbp    13f4:       75 ea                   jne    13e0     13f6:       48 83 c4 08             add    $0x8,%rsp    13fa:       5b                      pop    %rbx    13fb:       5d                      pop    %rbp    13fc:       41 5c                   pop    %r12    13fe:       41 5d                   pop    %r13    1400:       41 5e                   pop    %r14    1402:       41 5f                   pop    %r15    1404:       c3                      retq       1405:       66 66 2e 0f 1f 84 00    data16 nopw %cs:0x0(%rax,%rax,1)    140c:       00 00 00 00 

光看汇编代码有点难以理解,我们可以去查看glibc的源代码中的__libc_csu_init函数,其中关键代码部分:

void __libc_csu_init (int argc, char **argv, char **envp){...const size_t size = __init_array_end - __init_array_start;  for (size_t i = 0; i < size; i++)      (*__init_array_start [i]) (argc, argv, envp);     //事实上这个__init_array_satrt数组中就有全局对象构造函数的地址}...}

可以看出,__ libc_csu_init函数中会将__init_array_start数组中每个指针指向的函数执行一遍。

现在回到原来的问题,负责本编译单元所有全局\静态对象的构造和析构的_GLOBAL__sub_I_o1函数的指针被保存在__init_array_start数组中,也就是在__libc_csu_init函数中被调用的。

那么_GLOBAL__sub_I_o1函数的指针怎么被放进 __ init_array_start数组的呢?答案是,一旦一个目标文件里有一个这样的函数,编译器会在这个编译单元产生的目标文件(.o)文件的“.init_array”段中放置一个指针,这个指针指向的就是_GLOBAL__sub_I_a1函数。

//objdump -s ......Contents of section .init_array: 600dc8 b0054000 00000000 2d064000 00000000  ..@.....-.@...........

析构

在__lib_start_main 函数执行完main函数之后,执行exit函数:

void exit(int status){    while(__exit_func != NULL){        ...        __exit_funcs = __exit_funcs->next;      //__exit_funcs是存储由_cxa_atexit组成的函数的链表,                                                //这里的while循环则遍历该链表并逐个调用这些注册的函数        }    ...    _exit(status);                              //调用exit系统调用,进程直接结束}

总结

—>_start

​—>_lib_start_main

​—>__ libc_csu_init

​—>main

​—>__libc_csu_fini

_start---> _libc_start_main    ------> _libc_csu_init---------> _GLOBAL__sub_I_o1------------> _Z41__static_initialization_and_destruction_0ii---------------> _ZN6ObjectC1Ei  #全局构造函数------> main                #main函数------> exit---------> _ZN6ObjectD1Ev        #全局析构函数