2012年8月24日 星期五

c++ runtime - global object ctor (1) - 兩個 global object

env: g++ (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3

兩個 global object 和一個有什麼分別呢?恩 ... 沒分別, 不過誰要當老大呢?讓我們來看看有兩個 global object 的例子。

cppb.cpp
 1 __asm__(".code16gcc\n");
 2 #include "io.h"
 3 
 4 /*
 5  * c bootloader
 6  */
 7 
 8 //#define POINTER_TEST
 9 
10 
11 #define BOCHS_MB __asm__ __volatile__("xchg %bx, %bx");
12 
13 
14 Ab ab(7);
15 Io io;
16 
17 extern int _start_ctors;
18 extern int _end_ctors;
19 
20 extern "C" int cpp_main(void)
21 {
22   //BOCHS_MB  
23 
24   {
25   const char *ver=__VERSION__;
26   io.print("hello cpp class\r\n");
27   io.print("g++ version: ");
28   io.print(ver);
29   io.print("\r\n");
30   }
31   return 0;
32 }
33 
34 void *__dso_handle;
35 extern "C"
36 {
37 int __cxa_atexit(void (*destructor) (void *), void *arg, void *__dso_handle)
38 {
39   io.print("__cxa_atexit: register dtor here\r\n");
40   return 0;
41 }
42 }

這時候 g++ 產生的是 _GLOBAL__I_ab。
若是把 L14, L15 交換

15 Io io;
14 Ab ab(7);

g++ 會產生的 _GLOBAL__I_io, 很有趣吧!

objdump
 1 
 2 000001e1 <_Z41__static_initialization_and_destruction_0ii>:
 3  1e1:   66 55                   push   %ebp
 4  1e3:   66 89 e5                mov    %esp,%ebp
 5  1e6:   66 83 ec 18             sub    $0x18,%esp
 6  1ea:   67 66 83 7d 08 01       addr32 cmpl $0x1,0x8(%ebp)
 7  1f0:   75 7d                   jne    26f <_Z41__static_initialization_and_destruction_0ii+0x8e>
 8  1f2:   67 66 81 7d 0c ff ff    addr32 cmpl $0xffff,0xc(%ebp)
 9  1f9:   00 00 
10  1fb:   75 72                   jne    26f <_Z41__static_initialization_and_destruction_0ii+0x8e>
11  1fd:   67 66 c7 04 24 7c 10    addr32 movl $0x107c,(%esp)
12  204:   00 00 
13  206:   66 e8 e4 00 00 00       calll  2f0 <_ZN2IoC1Ev>
14  20c:   66 b8 6c 03 00 00       mov    $0x36c,%eax
15  212:   67 66 c7 44 24 08 88    addr32 movl $0x1088,0x8(%esp)
16  219:   10 00 00 
17  21c:   67 66 c7 44 24 04 7c    addr32 movl $0x107c,0x4(%esp)
18  223:   10 00 00 
19  226:   67 66 89 04 24          addr32 mov %eax,(%esp)
20  22b:   66 e8 84 ff ff ff       calll  1b5 <__cxa_atexit>
21  231:   67 66 c7 44 24 04 07    addr32 movl $0x7,0x4(%esp)
22  238:   00 00 00 
23  23b:   67 66 c7 04 24 80 10    addr32 movl $0x1080,(%esp)
24  242:   00 00 
25  244:   66 e8 c4 01 00 00       calll  40e <_ZN2AbC1Ei>
26  24a:   66 b8 6c 04 00 00       mov    $0x46c,%eax
27  250:   67 66 c7 44 24 08 88    addr32 movl $0x1088,0x8(%esp)
28  257:   10 00 00 
29  25a:   67 66 c7 44 24 04 80    addr32 movl $0x1080,0x4(%esp)
30  261:   10 00 00 
31  264:   67 66 89 04 24          addr32 mov %eax,(%esp)
32  269:   66 e8 46 ff ff ff       calll  1b5 <__cxa_atexit>
33  26f:   66 c9                   leavel 
34  271:   66 c3                   retl   
35 
36 00000273 <_GLOBAL__I_io>:
37  273:   66 55                   push   %ebp
38  275:   66 89 e5                mov    %esp,%ebp
39  278:   66 83 ec 18             sub    $0x18,%esp
40  27c:   67 66 c7 44 24 04 ff    addr32 movl $0xffff,0x4(%esp)
41  283:   ff 00 00 
42  286:   67 66 c7 04 24 01 00    addr32 movl $0x1,(%esp)
43  28d:   00 00 
44  28f:   66 e8 4c ff ff ff       calll  1e1 <_Z41__static_initialization_and_destruction_0ii>
45  295:   66 c9                   leavel 
46  297:   66 c3                   retl   

而有兩個 global object 的話, __static_initialization_and_destruction_0ii
會 invoke 兩次 __cxa_atexit 以及 Ab::Ab(7) 和 Io::Io() (L13, L25)。

11  1fd:   67 66 c7 04 24 7c 10    addr32 movl $0x107c,(%esp)
12  204:   00 00 
13  206:   66 e8 e4 00 00 00       calll  2f0 <_ZN2IoC1Ev>
 
21  231:   67 66 c7 44 24 04 07    addr32 movl $0x7,0x4(%esp) 
23  23b:   67 66 c7 04 24 80 10    addr32 movl $0x1080,(%esp)
24  242:   00 00 
25  244:   66 e8 c4 01 00 00       calll  40e <_ZN2AbC1Ei>

而 L11, L 23 0x107c, 0x1080 分別是 io, ab 這兩個  global object 的位址 (請自己用 readelf -a 查詢, 我懶得再貼了), 這就是 this 指標。L21 則是 Ab::Ab(7) 的參數 7。
也就是:

Io::Io() 但實際上是 Io::Io(&io)。

用 c 的話要自己傳入, 這麼固定的工作就交給 c++ compiler 了, 這也是 c++ 如此優雅的原因, 但了解背後的秘密是很重要的。

好吧!我還是貼了 ...

    19: 00001080     8 OBJECT  GLOBAL DEFAULT    5 ab
    20: 0000029c    83 FUNC    GLOBAL DEFAULT    1 _ZN2IoC2Ev
    21: 000004dc     0 NOTYPE  GLOBAL DEFAULT    2 __end_ctors
    22: 000004dc     0 NOTYPE  GLOBAL DEFAULT    3 _start_dtors
    23: 000004d8     0 NOTYPE  GLOBAL DEFAULT    2 start_ctors
    24: 00000344    39 FUNC    GLOBAL DEFAULT    1 _ZN2IoD2Ev
    25: 0000107c     0 NOTYPE  GLOBAL DEFAULT    5 __bss_start__
    26: 00001088     4 OBJECT  GLOBAL DEFAULT    5 __dso_handle
    27: 000004dc     0 NOTYPE  GLOBAL DEFAULT    3 _end_dtors
    28: 0000107c     0 NOTYPE  GLOBAL DEFAULT    5 sbss
    29: 000004dc     0 NOTYPE  GLOBAL DEFAULT    3 start_dtors
    30: 000003d8    54 FUNC    GLOBAL DEFAULT    1 _ZN2AbC2Ei
    31: 0000040e    54 FUNC    GLOBAL DEFAULT    1 _ZN2AbC1Ei
    32: 00000494    68 FUNC    GLOBAL DEFAULT    1 _ZN2Ab5printEPKc
    33: 000004d8     0 NOTYPE  GLOBAL DEFAULT    2 __start_ctors
    34: 0000107c     4 OBJECT  GLOBAL DEFAULT    5 io

沒有留言:

張貼留言

使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。

我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。