2012年9月16日 星期日

c++ runtime - dtor (1) 實作篇

原理篇之後, 我們來實作如何喚起 global object dtor。

cpp_abi.h
 1 __asm__(".code16gcc\n");
 2 
 3 #ifndef CPP_ABI_H
 4 #define CPP_ABI_H
 5 
 6 #define DOBJS_SIZE 3
 7 
 8 struct DObjs
 9 {
10   void (*dtor_) (void *);
11   void *arg_;
12   void *dso_handle_;
13 };
14 
15 extern "C"
16 {
17   int __cxa_atexit(void (*destructor) (void *), void *arg, void *__dso_handle);
18   void g_dtors(void);
19 }
20 
21 #endif

cpp_abi.h 補上需要的資訊, struct DObjs, 用來紀錄要調用呼叫的 dtor。

 6 #define DOBJS_SIZE 3

我宣告 size 為 3 的 DObjs array, 目前要用到的只有 io, ab 這兩個 globle object, 正確實作的話, 應該要去知道有幾個 global objects, 不過這裡我們就偷懶一下, 寫死就好。

int __cxa_atexit(void (*destructor) (void *), void *arg, void *__dso_handle);

則是要資訊紀錄在 DObjs 裡頭, 把每一個 dtor, this pointer, 紀錄下來,  __dso_handle 沒有用到, 我目前還搞不定 share objects。

void g_dtors(void);
呼叫每一個 global object dtor (依照建構時相反的順序)

參考以下 cpp_abi.cpp 實作。

cpp_abi.cpp
 1 #include "cpp_abi.h"
 2 
 3 void *__dso_handle;
 4 
 5 static DObjs dobjs[DOBJS_SIZE];
 6 int obj_count=0;
 7 
 8 void print_str(const char   *s);
 9 void s16_print_int(int i, int radix);
10 
11 extern "C"
12 {
13 
14   int __cxa_atexit(void (*destructor) (void *), void *arg, void *__dso_handle)
15   {
16     __asm__ __volatile__("xchg %bx, %bx");
17     print_str("atexit\r\n");
18     s16_print_int(obj_count, 10);
19     print_str("\r\n");
20 
21     dobjs[obj_count].dtor_ = destructor;
22     dobjs[obj_count].arg_ = arg;
23     dobjs[obj_count].dso_handle_ = __dso_handle;
24     ++obj_count;
25     return 0;
26   }
27   void g_dtors(void)
28   {
34     for (int i=obj_count-1 ; i >= 0 ; --i)
35     {
37       dobjs[i].dtor_(dobjs[i].arg_);
39     }
41   }
42 }

再來的程式就簡單了,  L84 就是呼叫 g_dtors, 直接把之前紀錄的 dtor 一個一個執行, 就完成在退出 cpp_main 時執行 global object 的解構。

整個 global objects ctor/dtor 的實作就是這樣, 沒有那麼神祕了吧!

cpp_init.S
  1 # init c++ runtime
  2 
  3 #define DOS
  4 
 30 .code16
 31 .extern __bss_start__
 32 .extern __bss_end__
 33 .extern __start_ctors
 34 .extern __end_ctors
 35 .extern cpp_main
 36 .extern obj_count
 37 
 38 
 39 .text
 40   jmp _start
 41 .global _start
 42 _start:
 43   xchg %bx, %bx
 44 #if 1
 45   mov %cs, %ax
 46   mov %ax, %ds
 47   mov %ax, %ss
 48 
 49 #endif
 
 73 
 74   call init_bss_asm # in dos need not init bss by myself
 
 80   # call _GLOBAL__I_XX invoke global object ctor, 
 81   # in dos environment use 16 or 32 bit address? look like 32 bit
 82   calll init_cpp_global_asm
 83   calll cpp_main
 84   calll g_dtors
 85 #  call disp_str2
 86   mov     $0x4c00, %ax
 87   int     $0x21   # 回到 DOS
 88 


109 
110 # call global object ctor
111 init_cpp_global_asm:
112 #if __GNUC__ >= 4 && __GNUC_MINOR__ >= 7
113   mov $__end_global_ctor__, %edi    /* Destination */
114   mov $__start_global_ctor__, %esi   /* Source */
115 #else
116   mov $__end_ctors, %edi    /* Destination */
117   mov $__start_ctors, %esi   /* Source */
118 #endif
119   jmp 2f
120 1:
121   mov %esi, %ebx 
122   calll *(%ebx)
123   add $4, %esi
124 2:
125   cmp %edi, %esi
126   jne 1b
127   ret
128 
129 # init bss
130 init_bss_asm:
131   movw $__bss_end__, %di    /* Destination */
132   movw $__bss_start__, %si   /* Source */
133   movw %ds, %bx
134   movw %bx, %es
135   jmp 2f
136 1:
137   mov $0, %eax
138   movw %si, %ax
139   movb $0x0, %es:(%eax)
140   add $1, %si
141 
142 
143   # wait key
144 #  xor %eax,%eax
145 #  int $0x16
146 
147   
148 2:
149   cmpw %di, %si
150   jne 1b
151 
152   ret
153 

再來要聊聊 local static object。

完整程式碼:
simple os: git clone git@github.com:descent/simple_os.git
git branch: cpp_runtime
git commit: 92e0183c722166c84da8b28aa11fd8afeff0ff6c
directory: simple_os/cpp_runtime/global_object/dos_cpp

沒有留言:

張貼留言

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

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