函数执行顺序

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-64

Disassembly of section .init:

0000000000001000 <_init>:
    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 <__gmon_start__>
    100f:       48 85 c0                test   %rax,%rax
    1012:       74 02                   je     1016 <_init+0x16>
    1014:       ff d0                   callq  *%rax
    1016:       48 83 c4 08             add    $0x8,%rsp
    101a:       c3                      retq   

Disassembly of section .plt:

0000000000001020 <.plt>:
    1020:       ff 35 62 2f 00 00       pushq  0x2f62(%rip)        # 3f88 <_GLOBAL_OFFSET_TABLE_+0x8>
    1026:       f2 ff 25 63 2f 00 00    bnd jmpq *0x2f63(%rip)        # 3f90 <_GLOBAL_OFFSET_TABLE_+0x10>
    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 <.plt>
    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 <.plt>
    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 <.plt>
    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 <.plt>
    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 <.plt>
    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 <.plt>
    108f:       90                      nop

Disassembly of section .plt.got:

0000000000001090 <__cxa_finalize@plt>:
    1090:       f3 0f 1e fa             endbr64 
    1094:       f2 ff 25 2d 2f 00 00    bnd jmpq *0x2f2d(%rip)        # 3fc8 <__cxa_finalize@GLIBC_2.2.5>
    109b:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)

Disassembly of section .plt.sec:

00000000000010a0 <__cxa_atexit@plt>:
    10a0:       f3 0f 1e fa             endbr64 
    10a4:       f2 ff 25 ed 2e 00 00    bnd jmpq *0x2eed(%rip)        # 3f98 <__cxa_atexit@GLIBC_2.2.5>
    10ab:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)

00000000000010b0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>:
    10b0:       f3 0f 1e fa             endbr64 
    10b4:       f2 ff 25 e5 2e 00 00    bnd jmpq *0x2ee5(%rip)        # 3fa0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@GLIBCXX_3.4>
    10bb:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)

00000000000010c0 <_ZNSolsEPFRSoS_E@plt>:
    10c0:       f3 0f 1e fa             endbr64 
    10c4:       f2 ff 25 dd 2e 00 00    bnd jmpq *0x2edd(%rip)        # 3fa8 <_ZNSolsEPFRSoS_E@GLIBCXX_3.4>
    10cb:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)

00000000000010d0 <__stack_chk_fail@plt>:
    10d0:       f3 0f 1e fa             endbr64 
    10d4:       f2 ff 25 d5 2e 00 00    bnd jmpq *0x2ed5(%rip)        # 3fb0 <__stack_chk_fail@GLIBC_2.4>
    10db:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)

00000000000010e0 <_ZNSt8ios_base4InitC1Ev@plt>:
    10e0:       f3 0f 1e fa             endbr64 
    10e4:       f2 ff 25 cd 2e 00 00    bnd jmpq *0x2ecd(%rip)        # 3fb8 <_ZNSt8ios_base4InitC1Ev@GLIBCXX_3.4>
    10eb:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)

00000000000010f0 <_ZNSolsEi@plt>:
    10f0:       f3 0f 1e fa             endbr64 
    10f4:       f2 ff 25 c5 2e 00 00    bnd jmpq *0x2ec5(%rip)        # 3fc0 <_ZNSolsEi@GLIBCXX_3.4>
    10fb:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)

Disassembly of section .text:

0000000000001100 <_start>:
    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 <__libc_csu_fini>
    111a:       48 8d 0d 7f 02 00 00    lea    0x27f(%rip),%rcx        # 13a0 <__libc_csu_init>
    1121:       48 8d 3d c1 00 00 00    lea    0xc1(%rip),%rdi        # 11e9 <main>
    1128:       ff 15 b2 2e 00 00       callq  *0x2eb2(%rip)        # 3fe0 <__libc_start_main@GLIBC_2.2.5>
    112e:       f4                      hlt    
    112f:       90                      nop

0000000000001130 <deregister_tm_clones>:
    1130:       48 8d 3d e1 2e 00 00    lea    0x2ee1(%rip),%rdi        # 4018 <__TMC_END__>
    1137:       48 8d 05 da 2e 00 00    lea    0x2eda(%rip),%rax        # 4018 <__TMC_END__>
    113e:       48 39 f8                cmp    %rdi,%rax
    1141:       74 15                   je     1158 <deregister_tm_clones+0x28>
    1143:       48 8b 05 8e 2e 00 00    mov    0x2e8e(%rip),%rax        # 3fd8 <_ITM_deregisterTMCloneTable>
    114a:       48 85 c0                test   %rax,%rax
    114d:       74 09                   je     1158 <deregister_tm_clones+0x28>
    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 <register_tm_clones>:
    1160:       48 8d 3d b1 2e 00 00    lea    0x2eb1(%rip),%rdi        # 4018 <__TMC_END__>
    1167:       48 8d 35 aa 2e 00 00    lea    0x2eaa(%rip),%rsi        # 4018 <__TMC_END__>
    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 <register_tm_clones+0x38>
    1184:       48 8b 05 65 2e 00 00    mov    0x2e65(%rip),%rax        # 3ff0 <_ITM_registerTMCloneTable>
    118b:       48 85 c0                test   %rax,%rax
    118e:       74 08                   je     1198 <register_tm_clones+0x38>
    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 <__do_global_dtors_aux>:
    11a0:       f3 0f 1e fa             endbr64 
    11a4:       80 3d a5 2f 00 00 00    cmpb   $0x0,0x2fa5(%rip)        # 4150 <completed.8060>
    11ab:       75 2b                   jne    11d8 <__do_global_dtors_aux+0x38>
    11ad:       55                      push   %rbp
    11ae:       48 83 3d 12 2e 00 00    cmpq   $0x0,0x2e12(%rip)        # 3fc8 <__cxa_finalize@GLIBC_2.2.5>
    11b5:       00 
    11b6:       48 89 e5                mov    %rsp,%rbp
    11b9:       74 0c                   je     11c7 <__do_global_dtors_aux+0x27>
    11bb:       48 8b 3d 46 2e 00 00    mov    0x2e46(%rip),%rdi        # 4008 <__dso_handle>
    11c2:       e8 c9 fe ff ff          callq  1090 <__cxa_finalize@plt>
    11c7:       e8 64 ff ff ff          callq  1130 <deregister_tm_clones>
    11cc:       c6 05 7d 2f 00 00 01    movb   $0x1,0x2f7d(%rip)        # 4150 <completed.8060>
    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 <frame_dummy>:
    11e0:       f3 0f 1e fa             endbr64 
    11e4:       e9 77 ff ff ff          jmpq   1160 <register_tm_clones>

00000000000011e9 <main>:
    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 <_ZN6ObjectC1Ei>
    1215:       48 8d 45 f4             lea    -0xc(%rbp),%rax
    1219:       48 89 c7                mov    %rax,%rdi
    121c:       e8 35 01 00 00          callq  1356 <_ZN6ObjectD1Ev>
    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 <main+0x51>
    1235:       e8 96 fe ff ff          callq  10d0 <__stack_chk_fail@plt>
    123a:       c9                      leaveq 
    123b:       c3                      retq   

000000000000123c <_Z41__static_initialization_and_destruction_0ii>:
    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 <_Z41__static_initialization_and_destruction_0ii+0xa4>
    1258:       81 7d f8 ff ff 00 00    cmpl   $0xffff,-0x8(%rbp)
    125f:       75 7f                   jne    12e0 <_Z41__static_initialization_and_destruction_0ii+0xa4>
    1261:       48 8d 3d f4 2e 00 00    lea    0x2ef4(%rip),%rdi        # 415c <_ZStL8__ioinit>
    1268:       e8 73 fe ff ff          callq  10e0 <_ZNSt8ios_base4InitC1Ev@plt>
    126d:       48 8d 15 94 2d 00 00    lea    0x2d94(%rip),%rdx        # 4008 <__dso_handle>
    1274:       48 8d 35 e1 2e 00 00    lea    0x2ee1(%rip),%rsi        # 415c <_ZStL8__ioinit>
    127b:       48 8b 05 76 2d 00 00    mov    0x2d76(%rip),%rax        # 3ff8 <_ZNSt8ios_base4InitD1Ev@GLIBCXX_3.4>
    1282:       48 89 c7                mov    %rax,%rdi
    1285:       e8 16 fe ff ff          callq  10a0 <__cxa_atexit@plt>
    128a:       be 01 00 00 00          mov    $0x1,%esi
    128f:       48 8d 3d be 2e 00 00    lea    0x2ebe(%rip),%rdi        # 4154 <o1>
    1296:       e8 61 00 00 00          callq  12fc <_ZN6ObjectC1Ei>
    129b:       48 8d 15 66 2d 00 00    lea    0x2d66(%rip),%rdx        # 4008 <__dso_handle>
    12a2:       48 8d 35 ab 2e 00 00    lea    0x2eab(%rip),%rsi        # 4154 <o1>
    12a9:       48 8d 3d a6 00 00 00    lea    0xa6(%rip),%rdi        # 1356 <_ZN6ObjectD1Ev>
    12b0:       e8 eb fd ff ff          callq  10a0 <__cxa_atexit@plt>
    12b5:       be 03 00 00 00          mov    $0x3,%esi
    12ba:       48 8d 3d 97 2e 00 00    lea    0x2e97(%rip),%rdi        # 4158 <o3>
    12c1:       e8 36 00 00 00          callq  12fc <_ZN6ObjectC1Ei>
    12c6:       48 8d 15 3b 2d 00 00    lea    0x2d3b(%rip),%rdx        # 4008 <__dso_handle>
    12cd:       48 8d 35 84 2e 00 00    lea    0x2e84(%rip),%rsi        # 4158 <o3>
    12d4:       48 8d 3d 7b 00 00 00    lea    0x7b(%rip),%rdi        # 1356 <_ZN6ObjectD1Ev>
    12db:       e8 c0 fd ff ff          callq  10a0 <__cxa_atexit@plt>
    12e0:       90                      nop
    12e1:       c9                      leaveq 
    12e2:       c3                      retq   

00000000000012e3 <_GLOBAL__sub_I_o1>:
    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 <_Z41__static_initialization_and_destruction_0ii>
    12fa:       5d                      pop    %rbp
    12fb:       c3                      retq   

00000000000012fc <_ZN6ObjectC1Ei>:
    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 <_ZStL19piecewise_construct+0x1>
    131f:       48 8d 3d 1a 2d 00 00    lea    0x2d1a(%rip),%rdi        # 4040 <_ZSt4cout@@GLIBCXX_3.4>
    1326:       e8 85 fd ff ff          callq  10b0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
    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 <_ZNSolsEi@plt>
    133e:       48 89 c2                mov    %rax,%rdx
    1341:       48 8b 05 88 2c 00 00    mov    0x2c88(%rip),%rax        # 3fd0 <_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GLIBCXX_3.4>
    1348:       48 89 c6                mov    %rax,%rsi
    134b:       48 89 d7                mov    %rdx,%rdi
    134e:       e8 6d fd ff ff          callq  10c0 <_ZNSolsEPFRSoS_E@plt>
    1353:       90                      nop
    1354:       c9                      leaveq 
    1355:       c3                      retq   

0000000000001356 <_ZN6ObjectD1Ev>:
    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 <_ZStL19piecewise_construct+0xa>
    136d:       48 8d 3d cc 2c 00 00    lea    0x2ccc(%rip),%rdi        # 4040 <_ZSt4cout@@GLIBCXX_3.4>
    1374:       e8 37 fd ff ff          callq  10b0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
    1379:       48 89 c2                mov    %rax,%rdx
    137c:       48 8b 05 4d 2c 00 00    mov    0x2c4d(%rip),%rax        # 3fd0 <_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GLIBCXX_3.4>
    1383:       48 89 c6                mov    %rax,%rsi
    1386:       48 89 d7                mov    %rdx,%rdi
    1389:       e8 32 fd ff ff          callq  10c0 <_ZNSolsEPFRSoS_E@plt>
    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 <__libc_csu_init>:
    13a0:       f3 0f 1e fa             endbr64 
    13a4:       41 57                   push   %r15
    13a6:       4c 8d 3d bb 29 00 00    lea    0x29bb(%rip),%r15        # 3d68 <__frame_dummy_init_array_entry>
    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 <__do_global_dtors_aux_fini_array_entry>
    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 <_init>
    13d1:       48 c1 fd 03             sar    $0x3,%rbp
    13d5:       74 1f                   je     13f6 <__libc_csu_init+0x56>
    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 <__libc_csu_init+0x40>
    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 <__libc_csu_fini>:
    1410:       f3 0f 1e fa             endbr64 
    1414:       c3                      retq   

Disassembly of section .fini:

0000000000001418 <_fini>:
    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 <main>:
    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 <_ZN6ObjectC1Ei>
    1215:       48 8d 45 f4             lea    -0xc(%rbp),%rax
    1219:       48 89 c7                mov    %rax,%rdi
    121c:       e8 35 01 00 00          callq  1356 <_ZN6ObjectD1Ev>
    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 <main+0x51>
    1235:       e8 96 fe ff ff          callq  10d0 <__stack_chk_fail@plt>
    123a:       c9                      leaveq 
    123b:       c3                      retq   
从main函数的反汇编代码中,我们可以看出,在main函数只构造了o2这一个对象,o2的构造函数被命名为 _ZN6ObjectC1Ei,析构函数被命名为 _ZN6ObjectD1Ev。

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

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

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

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

构造函数:

00000000000012fc <_ZN6ObjectC1Ei>:
    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 <_ZStL19piecewise_construct+0x1>
    131f:       48 8d 3d 1a 2d 00 00    lea    0x2d1a(%rip),%rdi        # 4040 <_ZSt4cout@@GLIBCXX_3.4>
    1326:       e8 85 fd ff ff          callq  10b0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
    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 <_ZNSolsEi@plt>
    133e:       48 89 c2                mov    %rax,%rdx
    1341:       48 8b 05 88 2c 00 00    mov    0x2c88(%rip),%rax        # 3fd0 <_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GLIBCXX_3.4>
    1348:       48 89 c6                mov    %rax,%rsi
    134b:       48 89 d7                mov    %rdx,%rdi
    134e:       e8 6d fd ff ff          callq  10c0 <_ZNSolsEPFRSoS_E@plt>
    1353:       90                      nop
    1354:       c9                      leaveq 
    1355:       c3                      retq   

析构函数:

0000000000001356 <_ZN6ObjectD1Ev>:
    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 <_ZStL19piecewise_construct+0xa>
    136d:       48 8d 3d cc 2c 00 00    lea    0x2ccc(%rip),%rdi        # 4040 <_ZSt4cout@@GLIBCXX_3.4>
    1374:       e8 37 fd ff ff          callq  10b0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
    1379:       48 89 c2                mov    %rax,%rdx
    137c:       48 8b 05 4d 2c 00 00    mov    0x2c4d(%rip),%rax        # 3fd0 <_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GLIBCXX_3.4>
    1383:       48 89 c6                mov    %rax,%rsi
    1386:       48 89 d7                mov    %rdx,%rdi
    1389:       e8 32 fd ff ff          callq  10c0 <_ZNSolsEPFRSoS_E@plt>
    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 <_Z41__static_initialization_and_destruction_0ii>:
    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 <_Z41__static_initialization_and_destruction_0ii+0xa4>
    1258:       81 7d f8 ff ff 00 00    cmpl   $0xffff,-0x8(%rbp)
    125f:       75 7f                   jne    12e0 <_Z41__static_initialization_and_destruction_0ii+0xa4>
    1261:       48 8d 3d f4 2e 00 00    lea    0x2ef4(%rip),%rdi        # 415c <_ZStL8__ioinit>
    1268:       e8 73 fe ff ff          callq  10e0 <_ZNSt8ios_base4InitC1Ev@plt>
    126d:       48 8d 15 94 2d 00 00    lea    0x2d94(%rip),%rdx        # 4008 <__dso_handle>
    1274:       48 8d 35 e1 2e 00 00    lea    0x2ee1(%rip),%rsi        # 415c <_ZStL8__ioinit>
    127b:       48 8b 05 76 2d 00 00    mov    0x2d76(%rip),%rax        # 3ff8 <_ZNSt8ios_base4InitD1Ev@GLIBCXX_3.4>
    1282:       48 89 c7                mov    %rax,%rdi
    1285:       e8 16 fe ff ff          callq  10a0<__cxa_atexit@plt>
    128a:       be 01 00 00 00          mov    $0x1,%esi
    128f:       48 8d 3d be 2e 00 00    lea    0x2ebe(%rip),%rdi        # 4154 <o1>
    1296:       e8 61 00 00 00          callq  12fc <_ZN6ObjectC1Ei>
    129b:       48 8d 15 66 2d 00 00    lea    0x2d66(%rip),%rdx        # 4008 <__dso_handle>
    12a2:       48 8d 35 ab 2e 00 00    lea    0x2eab(%rip),%rsi        # 4154 <o1>
    12a9:       48 8d 3d a6 00 00 00    lea    0xa6(%rip),%rdi        # 1356 <_ZN6ObjectD1Ev>
    12b0:       e8 eb fd ff ff          callq  10a0<__cxa_atexit@plt>
    12b5:       be 03 00 00 00          mov    $0x3,%esi
    12ba:       48 8d 3d 97 2e 00 00    lea    0x2e97(%rip),%rdi        # 4158 <o3>
    12c1:       e8 36 00 00 00          callq  12fc <_ZN6ObjectC1Ei>
    12c6:       48 8d 15 3b 2d 00 00    lea    0x2d3b(%rip),%rdx        # 4008 <__dso_handle>
    12cd:       48 8d 35 84 2e 00 00    lea    0x2e84(%rip),%rsi        # 4158 <o3>
    12d4:       48 8d 3d 7b 00 00 00    lea    0x7b(%rip),%rdi        # 1356 <_ZN6ObjectD1Ev>
    12db:       e8 c0 fd ff ff          callq  10a0<__cxa_atexit@plt>
    12e0:       90                      nop
    12e1:       c9                      leaveq 
    12e2:       c3                      retq   

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

第21行调用构造函数,

第25行调用回调函数,

第28行调用构造函数。

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


 00000000000012e3 <_GLOBAL__sub_I_o1>:
    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 <_Z41__static_initialization_and_destruction_0ii>
    12fa:       5d                      pop    %rbp
    12fb:       c3                      retq   

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

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

程序的入口

程序入口:_start

0000000000001100 <_start>:
    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 <__libc_csu_fini>
    111a:       48 8d 0d 7f 02 00 00    lea    0x27f(%rip),%rcx        # 13a0 <__libc_csu_init>
    1121:       48 8d 3d c1 00 00 00    lea    0xc1(%rip),%rdi        # 11e9 <main>
    1128:       ff 15 b2 2e 00 00       callq  *0x2eb2(%rip)        # 3fe0 <__libc_start_main@GLIBC_2.2.5>
    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 <__libc_csu_init>:
    13a0:       f3 0f 1e fa             endbr64 
    13a4:       41 57                   push   %r15
    13a6:       4c 8d 3d bb 29 00 00    lea    0x29bb(%rip),%r15        # 3d68 <__frame_dummy_init_array_entry>
    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 <__do_global_dtors_aux_fini_array_entry>
    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 <_init>
    13d1:       48 c1 fd 03             sar    $0x3,%rbp
    13d5:       74 1f                   je     13f6 <__libc_csu_init+0x56>
    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 <__libc_csu_init+0x40>
    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        #全局析构函数

posted @ 2023-01-12 16:43  baobaobashi  阅读(120)  评论(0编辑  收藏  举报