2015年3月8日 星期日

c++ runtime - global object ctor (0)

the 1st edition: 20120826
the 2nd edition: 20150308

請先參考以下文章, 了解整個來龍去脈:
  1. 作業系統之前的程式 (1) - c++ 篇
  2. 作業系統之前的程式 (2) - c++ global object ctor/dtor can not be invoked

自己真的是豬頭, 我明明就已經看完《程式設計師的自我修養: 連結、載入、程式庫》這本書, 卻完全不記得書中就有提到 c++ global object runtime, 還辛苦的找尋網路資料以及使用 objdump, readelf, 想透過反組譯追這些資料。

可見我只是看完這本書, 但離真正的理解還有一段距離, 書中的知識不太會用在一般軟體開發上, 要不是自己嘗試用 asm + c/c++ 來開發 os, 我也不會和 objdump, readelf 這些東西打交道。

自己用 objdump, readelf 胡亂嘗試的時間並沒有白廢, 和書中對照後, 我更能體會書中寫的東西。還蠻得意的, 我沒有看 g++ source code, 僅僅用了 c++filt, nm, objdump, readelf, gdb 就推測出書中的部份論述。

書中提到東西我自然不會再寫一次, 這裡僅說明我的觀察, 讓我們從 elf 開始:

readelf -a cppb.elf |
  1 ELF Header:
  2   Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  3   Class:                             ELF32
  4   Data:                              2's complement, little endian
  5   Version:                           1 (current)
  6   OS/ABI:                            UNIX - System V
  7   ABI Version:                       0
  8   Type:                              EXEC (Executable file)
  9   Machine:                           Intel 80386
 10   Version:                           0x1
 11   Entry point address:               0x100
 12   Start of program headers:          52 (bytes into file)
 13   Start of section headers:          7224 (bytes into file)
 14   Flags:                             0x0
 15   Size of this header:               52 (bytes)
 16   Size of program headers:           32 (bytes)
 17   Number of program headers:         3
 18   Size of section headers:           40 (bytes)
 19   Number of section headers:         17
 20   Section header string table index: 14
 21 
 22 Section Headers:
 23   [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
 24   [ 0]                   NULL            00000000 000000 000000 00      0   0  0
 25   [ 1] .text             PROGBITS        00000100 000100 000290 00  AX  0   0  4
 26   [ 2] .ctors            PROGBITS        00000390 000390 000004 00  WA  0   0  4
 27   [ 3] .dtors            NOBITS          00000394 000394 000c6c 00  WA  0   0  1
 28   [ 4] .rodata           PROGBITS        00001000 001000 000061 00   A  0   0  1
 29   [ 5] .bss              NOBITS          00001064 001061 000008 00  WA  0   0  4
 30   [ 6] .debug_abbrev     PROGBITS        00000000 001061 000238 00      0   0  1
 31   [ 7] .debug_info       PROGBITS        00000000 001299 00035d 00      0   0  1
 32   [ 8] .debug_line       PROGBITS        00000000 0015f6 0000c5 00      0   0  1
 33   [ 9] .debug_loc        PROGBITS        00000000 0016bb 0001b8 00      0   0  1
 34   [10] .debug_pubnames   PROGBITS        00000000 001873 0000a8 00      0   0  1
 35   [11] .debug_aranges    PROGBITS        00000000 00191b 000040 00      0   0  1
 36   [12] .debug_str        PROGBITS        00000000 00195b 00011d 01  MS  0   0  1
 37   [13] .debug_frame      PROGBITS        00000000 001a78 00011c 00      0   0  4
 38   [14] .shstrtab         STRTAB          00000000 001b94 0000a4 00      0   0  1
 39   [15] .symtab           SYMTAB          00000000 001ee0 0002a0 10     16  18  4
 40   [16] .strtab           STRTAB          00000000 002180 00015a 00      0   0  1
 41 Key to Flags:
 42   W (write), A (alloc), X (execute), M (merge), S (strings)
 43   I (info), L (link order), G (group), x (unknown)
 44   O (extra OS processing required) o (OS specific), p (processor specific)
 45 
 46 There are no section groups in this file.
 47 
 48 Program Headers:
 49   Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
 50   LOAD           0x000000 0x00000000 0x00007b00 0x00394 0x01000 RWE 0x1000
 51   LOAD           0x001000 0x00001000 0x00008b00 0x00061 0x0006c RW  0x1000
 52   GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x4
 53 
 54  Section to Segment mapping:
 55   Segment Sections...
 56    00     .text .ctors .dtors 
 57    01     .rodata .bss 
 58    02     
 59 
 60 There is no dynamic section in this file.
 61 
 62 There are no relocations in this file.
 63 
 64 There are no unwind sections in this file.
 65 
 66 Symbol table '.symtab' contains 42 entries:
 67    Num:    Value  Size Type    Bind   Vis      Ndx Name
 68      0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
 69      1: 00000100     0 SECTION LOCAL  DEFAULT    1 
 70      2: 00000390     0 SECTION LOCAL  DEFAULT    2 
 71      3: 00000394     0 SECTION LOCAL  DEFAULT    3 
 72      4: 00001000     0 SECTION LOCAL  DEFAULT    4 
 73      5: 00001064     0 SECTION LOCAL  DEFAULT    5 
 74      6: 00000000     0 SECTION LOCAL  DEFAULT    6 
 75      7: 00000000     0 SECTION LOCAL  DEFAULT    7 
 76      8: 00000000     0 SECTION LOCAL  DEFAULT    8 
 77      9: 00000000     0 SECTION LOCAL  DEFAULT    9 
 78     10: 00000000     0 SECTION LOCAL  DEFAULT   10 
 79     11: 00000000     0 SECTION LOCAL  DEFAULT   11 
 80     12: 00000000     0 SECTION LOCAL  DEFAULT   12 
 81     13: 00000000     0 SECTION LOCAL  DEFAULT   13 
 82     14: 00000000     0 FILE    LOCAL  DEFAULT  ABS cppb.cpp
 83     15: 0000022e    38 FUNC    LOCAL  DEFAULT    1 _GLOBAL__I_io
 84     16: 000001da    84 FUNC    LOCAL  DEFAULT    1 _Z41__static_initializati
 85     17: 00000000     0 FILE    LOCAL  DEFAULT  ABS io.cpp
 86     18: 00000254    83 FUNC    GLOBAL DEFAULT    1 _ZN2IoC2Ev
 87     19: 00000394     0 NOTYPE  GLOBAL DEFAULT    2 __end_ctors
 88     20: 00000394     0 NOTYPE  GLOBAL DEFAULT    3 _start_dtors
 89     21: 00000390     0 NOTYPE  GLOBAL DEFAULT    2 start_ctors
 90     22: 000001b4    38 FUNC    GLOBAL DEFAULT    1 __cxa_finalize
 91     23: 000002fc    39 FUNC    GLOBAL DEFAULT    1 _ZN2IoD2Ev
 92     24: 00001068     4 OBJECT  GLOBAL DEFAULT    5 __dso_handle
 93     25: 00000394     0 NOTYPE  GLOBAL DEFAULT    3 _end_dtors
 94     26: 00001064     0 NOTYPE  GLOBAL DEFAULT    5 sbss
 95     27: 00000394     0 NOTYPE  GLOBAL DEFAULT    3 start_dtors
 96     28: 00000390     0 NOTYPE  GLOBAL DEFAULT    2 __start_ctors
 97     29: 00001064     4 OBJECT  GLOBAL DEFAULT    5 io
 98     30: 00000394     0 NOTYPE  GLOBAL DEFAULT    2 _end_ctors
 99     31: 00000188    44 FUNC    GLOBAL DEFAULT    1 __cxa_atexit
100     32: 00000394     0 NOTYPE  GLOBAL DEFAULT    2 end_ctors
101     33: 00000100   136 FUNC    GLOBAL DEFAULT    1 WinMain
102     34: 00000394     0 NOTYPE  GLOBAL DEFAULT    3 end_dtors
103     35: 00000394     0 NOTYPE  GLOBAL DEFAULT    3 __end_dtors
104     36: 000002a8    83 FUNC    GLOBAL DEFAULT    1 _ZN2IoC1Ev
105     37: 0000106c     0 NOTYPE  GLOBAL DEFAULT    5 ebss
106     38: 00000394     0 NOTYPE  GLOBAL DEFAULT    3 __start_dtors
107     39: 00000390     0 NOTYPE  GLOBAL DEFAULT    2 _start_ctors
108     40: 0000034c    68 FUNC    GLOBAL DEFAULT    1 _ZN2Io5printEPKc
109     41: 00000324    39 FUNC    GLOBAL DEFAULT    1 _ZN2IoD1Ev
110 
111 No version information found in this file.

elf dump 很長, 但是只要看第 26 行就好, 其他是我拿來佔篇幅用的。神祕的 .ctors section 有著我們要的線索。

 26   [ 2] .ctors            PROGBITS        00000390 000390 000004 00  WA  0   0  4

.ctors section 佔了 4 byte,

看看 cppb.elf 0x390 是什麼:
00000390  2e 02 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

cppb.elf offset 390 的內容是 2e02 => little endian is 022e

 87 0000022e <_GLOBAL__I_io>:

這麼巧, 022e 就是 _GLOBAL__I_io (L87) 這個 symbol (g++ 版本不同, 這個 symbol 會不同) 的位址:

objdump -m i8086 -d cppb.elf
  1 
  2 cppb.elf:     file format elf32-i386
  3 
  4 
  5 Disassembly of section .text:
  6 
  7 00000100 <WinMain>:
  8  100: 66 55                 push   %ebp
  9  102: 66 89 e5              mov    %esp,%ebp
 10  105: 66 83 ec 28           sub    $0x28,%esp
 11  109: 87 db                 xchg   %bx,%bx
 12  10b: 66 e8 1d 01 00 00     calll  22e <_GLOBAL__I_io>
 13  111: 67 66 c7 45 f4 00 10  addr32 movl $0x1000,-0xc(%ebp)
 14  118: 00 00 
 15  11a: 67 66 c7 44 24 04 06  addr32 movl $0x1006,0x4(%esp)
 16  121: 10 00 00 
 17  124: 67 66 c7 04 24 64 10  addr32 movl $0x1064,(%esp)
 18  12b: 00 00 
 19  12d: 66 e8 19 02 00 00     calll  34c <_ZN2Io5printEPKc>
 20  133: 67 66 c7 44 24 04 18  addr32 movl $0x1018,0x4(%esp)
 21  13a: 10 00 00 
 22  13d: 67 66 c7 04 24 64 10  addr32 movl $0x1064,(%esp)
 23  144: 00 00 
 24  146: 66 e8 00 02 00 00     calll  34c <_ZN2Io5printEPKc>
 25  14c: 67 66 8b 45 f4        addr32 mov -0xc(%ebp),%eax
 26  151: 67 66 89 44 24 04     addr32 mov %eax,0x4(%esp)
 27  157: 67 66 c7 04 24 64 10  addr32 movl $0x1064,(%esp)
 28  15e: 00 00 
 29  160: 66 e8 e6 01 00 00     calll  34c <_ZN2Io5printEPKc>
 30  166: 67 66 c7 44 24 04 26  addr32 movl $0x1026,0x4(%esp)
 31  16d: 10 00 00 
 32  170: 67 66 c7 04 24 64 10  addr32 movl $0x1064,(%esp)
 33  177: 00 00 
 34  179: 66 e8 cd 01 00 00     calll  34c <_ZN2Io5printEPKc>
 35  17f: b8 00 4c              mov    $0x4c00,%ax
 36  182: cd 21                 int    $0x21
 37  184: 66 c9                 leavel 
 38  186: 66 c3                 retl   
 39 
 40 00000188 <__cxa_atexit>:
 41  188: 66 55                 push   %ebp
 42  18a: 66 89 e5              mov    %esp,%ebp
 43  18d: 66 83 ec 18           sub    $0x18,%esp
 44  191: 67 66 c7 44 24 04 29  addr32 movl $0x1029,0x4(%esp)
 45  198: 10 00 00 
 46  19b: 67 66 c7 04 24 64 10  addr32 movl $0x1064,(%esp)
 47  1a2: 00 00 
 48  1a4: 66 e8 a2 01 00 00     calll  34c <_ZN2Io5printEPKc>
 49  1aa: 66 b8 00 00 00 00     mov    $0x0,%eax
 50  1b0: 66 c9                 leavel 
 51  1b2: 66 c3                 retl   
 52 
 53 000001b4 <__cxa_finalize>:
 54  1b4: 66 55                 push   %ebp
 55  1b6: 66 89 e5              mov    %esp,%ebp
 56  1b9: 66 83 ec 18           sub    $0x18,%esp
 57  1bd: 67 66 c7 44 24 04 38  addr32 movl $0x1038,0x4(%esp)
 58  1c4: 10 00 00 
 59  1c7: 67 66 c7 04 24 64 10  addr32 movl $0x1064,(%esp)
 60  1ce: 00 00 
 61  1d0: 66 e8 76 01 00 00     calll  34c <_ZN2Io5printEPKc>
 62  1d6: 66 c9                 leavel 
 63  1d8: 66 c3                 retl   
 64 
 65 000001da <_Z41__static_initialization_and_destruction_0ii>:
 66  1da: 66 55                 push   %ebp
 67  1dc: 66 89 e5              mov    %esp,%ebp
 68  1df: 66 83 ec 18           sub    $0x18,%esp
 69  1e3: 67 66 83 7d 08 01     addr32 cmpl $0x1,0x8(%ebp)
 70  1e9: 75 3f                 jne    22a <_Z41__static_initialization_and_destruction_0ii+0x50>
 71  1eb: 67 66 81 7d 0c ff ff  addr32 cmpl $0xffff,0xc(%ebp)
 72  1f2: 00 00 
 73  1f4: 75 34                 jne    22a <_Z41__static_initialization_and_destruction_0ii+0x50>
 74  1f6: 67 66 c7 04 24 64 10  addr32 movl $0x1064,(%esp)
 75  1fd: 00 00 
 76  1ff: 66 e8 a3 00 00 00     calll  2a8 <_ZN2IoC1Ev>
 77  205: 66 b8 24 03 00 00     mov    $0x324,%eax
 78  20b: 67 66 c7 44 24 08 68  addr32 movl $0x1068,0x8(%esp)
 79  212: 10 00 00 
 80  215: 67 66 c7 44 24 04 64  addr32 movl $0x1064,0x4(%esp)
 81  21c: 10 00 00 
 82  21f: 67 66 89 04 24        addr32 mov %eax,(%esp)
 83  224: 66 e8 5e ff ff ff     calll  188 <__cxa_atexit>
 84  22a: 66 c9                 leavel 
 85  22c: 66 c3                 retl   
 86 
 87 0000022e <_GLOBAL__I_io>:
 88  22e: 66 55                 push   %ebp
 89  230: 66 89 e5              mov    %esp,%ebp
 90  233: 66 83 ec 18           sub    $0x18,%esp
 91  237: 67 66 c7 44 24 04 ff  addr32 movl $0xffff,0x4(%esp)
 92  23e: ff 00 00 
 93  241: 67 66 c7 04 24 01 00  addr32 movl $0x1,(%esp)
 94  248: 00 00 
 95  24a: 66 e8 8a ff ff ff     calll  1da <_Z41__static_initialization_and_destruction_0ii>
 96  250: 66 c9                 leavel 
 97  252: 66 c3                 retl   
 98 
 99 00000254 <_ZN2IoC2Ev>:
100  254: 66 55                 push   %ebp
101  256: 66 89 e5              mov    %esp,%ebp
102  259: 66 83 ec 18           sub    $0x18,%esp
103  25d: 67 66 8b 45 08        addr32 mov 0x8(%ebp),%eax
104  262: 67 66 c7 00 45 10 00  addr32 movl $0x1045,(%eax)
105  269: 00 
106  26a: 67 66 c7 44 24 04 53  addr32 movl $0x1053,0x4(%esp)
107  271: 10 00 00 
108  274: 67 66 8b 45 08        addr32 mov 0x8(%ebp),%eax
109  279: 67 66 89 04 24        addr32 mov %eax,(%esp)
110  27e: 66 e8 c8 00 00 00     calll  34c <_ZN2Io5printEPKc>
111  284: 67 66 8b 45 08        addr32 mov 0x8(%ebp),%eax
112  289: 67 66 8b 00           addr32 mov (%eax),%eax
113  28d: 67 66 89 44 24 04     addr32 mov %eax,0x4(%esp)
114  293: 67 66 8b 45 08        addr32 mov 0x8(%ebp),%eax
115  298: 67 66 89 04 24        addr32 mov %eax,(%esp)
116  29d: 66 e8 a9 00 00 00     calll  34c <_ZN2Io5printEPKc>
117  2a3: 66 c9                 leavel 
118  2a5: 66 c3                 retl   
119  2a7: 90                    nop
120 
121 000002a8 <_ZN2IoC1Ev>:
122  2a8: 66 55                 push   %ebp
123  2aa: 66 89 e5              mov    %esp,%ebp
124  2ad: 66 83 ec 18           sub    $0x18,%esp
125  2b1: 67 66 8b 45 08        addr32 mov 0x8(%ebp),%eax
126  2b6: 67 66 c7 00 45 10 00  addr32 movl $0x1045,(%eax)
127  2bd: 00 
128  2be: 67 66 c7 44 24 04 53  addr32 movl $0x1053,0x4(%esp)
129  2c5: 10 00 00 
130  2c8: 67 66 8b 45 08        addr32 mov 0x8(%ebp),%eax
131  2cd: 67 66 89 04 24        addr32 mov %eax,(%esp)
132  2d2: 66 e8 74 00 00 00     calll  34c <_ZN2Io5printEPKc>
133  2d8: 67 66 8b 45 08        addr32 mov 0x8(%ebp),%eax
134  2dd: 67 66 8b 00           addr32 mov (%eax),%eax
135  2e1: 67 66 89 44 24 04     addr32 mov %eax,0x4(%esp)
136  2e7: 67 66 8b 45 08        addr32 mov 0x8(%ebp),%eax
137  2ec: 67 66 89 04 24        addr32 mov %eax,(%esp)
138  2f1: 66 e8 55 00 00 00     calll  34c <_ZN2Io5printEPKc>
139  2f7: 66 c9                 leavel 
140  2f9: 66 c3                 retl   
141  2fb: 90                    nop
142 
143 000002fc <_ZN2IoD2Ev>:
144  2fc: 66 55                 push   %ebp
145  2fe: 66 89 e5              mov    %esp,%ebp
146  301: 66 83 ec 18           sub    $0x18,%esp
147  305: 67 66 c7 44 24 04 5a  addr32 movl $0x105a,0x4(%esp)
148  30c: 10 00 00 
149  30f: 67 66 8b 45 08        addr32 mov 0x8(%ebp),%eax
150  314: 67 66 89 04 24        addr32 mov %eax,(%esp)
151  319: 66 e8 2d 00 00 00     calll  34c <_ZN2Io5printEPKc>
152  31f: 66 c9                 leavel 
153  321: 66 c3                 retl   
154  323: 90                    nop
155 
156 00000324 <_ZN2IoD1Ev>:
157  324: 66 55                 push   %ebp
158  326: 66 89 e5              mov    %esp,%ebp
159  329: 66 83 ec 18           sub    $0x18,%esp
160  32d: 67 66 c7 44 24 04 5a  addr32 movl $0x105a,0x4(%esp)
161  334: 10 00 00 
162  337: 67 66 8b 45 08        addr32 mov 0x8(%ebp),%eax
163  33c: 67 66 89 04 24        addr32 mov %eax,(%esp)
164  341: 66 e8 05 00 00 00     calll  34c <_ZN2Io5printEPKc>
165  347: 66 c9                 leavel 
166  349: 66 c3                 retl   
167  34b: 90                    nop
168 
169 0000034c <_ZN2Io5printEPKc>:
170  34c: 66 55                 push   %ebp
171  34e: 66 89 e5              mov    %esp,%ebp
172  351: 66 53                 push   %ebx
173  353: eb 22                 jmp    377 <_ZN2Io5printEPKc+0x2b>
174  355: 67 66 8b 45 0c        addr32 mov 0xc(%ebp),%eax
175  35a: 67 66 0f b6 00        addr32 movzbl (%eax),%eax
176  35f: 66 0f be c0           movsbl %al,%eax
177  363: 80 cc 0e              or     $0xe,%ah
178  366: 66 ba 07 00 00 00     mov    $0x7,%edx
179  36c: 66 89 d3              mov    %edx,%ebx
180  36f: cd 10                 int    $0x10
181  371: 67 66 83 45 0c 01     addr32 addl $0x1,0xc(%ebp)
182  377: 67 66 8b 45 0c        addr32 mov 0xc(%ebp),%eax
183  37c: 67 66 0f b6 00        addr32 movzbl (%eax),%eax
184  381: 84 c0                 test   %al,%al
185  383: 0f 95 c0              setne  %al
186  386: 84 c0                 test   %al,%al
187  388: 75 cb                 jne    355 <_ZN2Io5printEPKc+0x9>
188  38a: 66 5b                 pop    %ebx
189  38c: 66 5d                 pop    %ebp
190  38e: 66 c3                 retl   

022e 是 _GLOBAL__I_io,
_GLOBAL__I_io call
_Z41__static_initialization_and_destruction_0ii call
_ZN2IoC1Ev (ctor)

這就是 global ctor (_ZN2IoC1Ev) 被喚起的秘密。

所以僅僅宣告了 global object, g++ 就幫我們加入了
_GLOBAL__I_io
_Z41__static_initialization_and_destruction_0ii call
這兩個 funcion (還有其他 function, 暫不說明, 不知道的東西如何說明 XD)

那要怎麼才能執行 global ctor 呢?手動呼叫 (我才不用調用這術語, 保留台灣味) _GLOBAL__I_io 就搞定了。你一定覺得很蠢, 那我不是每次都要自己 nm 一下, 把 symbol name 找出來。

放心, 雖然本範例是用這樣的方式, 但我可不打算這樣用:
.ctors section
就存放著位址, 抓出來直接 call 就好了。如何做呢?下一篇再來解釋 ...

下面分別為這次測試的 c++ source code, linker script, 編譯方式。
g++ version : 4.4

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   Io io;
15 
16 extern int _start_ctors;
17 extern int _end_ctors;
18 
19 extern "C" void WinMain(void)
20 {
21 
22   BOCHS_MB  
23   #if 1
24   //__asm__ ("mov  %cs, %ax\n");
25   //__asm__ ("mov  %ax, %ds\n");
26   //__asm__ ("mov  %ax, %ss\n");
27 
28 #if 0
29   int ctor_addr_start = _start_ctors;
30   int ctor_addr_end = _end_ctors;
31     typedef void (*FuncPtr)();
32     FuncPtr fp = (FuncPtr)(ctor_addr_start);
33     fp();
34 #endif
35 
36 /* Test for GCC > 3.2.0 
37  * ref: http://gcc.gnu.org/onlinedocs/gcc-3.4.6/cpp/Common-Predefined-Macros.html
38   #if __GNUC__ > 3 || \
39   (__GNUC__ == 3 && (__GNUC_MINOR__ > 2 || \
40   (__GNUC_MINOR__ == 2 && \
41   __GNUC_PATCHLEVEL__ > 0))
42 */
43 
44   #if __GNUC__ >= 4 && __GNUC_MINOR__ <= 4
45   extern void _GLOBAL__I_io();
46   _GLOBAL__I_io();
47   #else // for 4.7
48   extern void _GLOBAL__sub_I_io();
49   _GLOBAL__sub_I_io();
50   #endif
51     #if 0
52   for (int i = ctor_addr_start; i < ctor_addr_end ; ++i)
53   {
54   }
55 
56 #endif
57   //__asm__ ("mov  $0xfff0, %sp\n");
58   {
59   const char *ver=__VERSION__;
60   io.print("hello cpp class\r\n");
61   io.print("g++ version: ");
62   io.print(ver);
63   io.print("\r\n");
64   }
65   #if 0
66   unsigned char *vb = (unsigned char *)0xb8000;
67   *vb = 'A';
68   *(unsigned char *)0xb8001 = 0xc;
69   *(unsigned char *)0xb8002 = 'B';
70   *(unsigned char *)0xb8003 = 0x9;
71   *(unsigned char *)0xb8004 = '@';
72   *(unsigned char *)0xb8005 = 0xc;
73   #endif
74   //while(1);
75   __asm__ ("mov     $0x4c00, %ax\n");
76   __asm__ ("int     $0x21\n"); //   回到 DOS
77 
78   #endif
79 }
80 
81 
82 
83 void *__dso_handle;
84 extern "C"
85 {
86 int __cxa_atexit(void (*destructor) (void *), void *arg, void *__dso_handle)
87 {
88   io.print("__cxa_atexit\r\n");
89   return 0;
90 }
91 void __cxa_finalize(void *d)
92 {
93   io.print("hello dtor\r\n");
94 }
95 }

cpp.ld
 1 /* for cb.c */
 2 ENTRY(WinMain);
 3 SECTIONS
 4 {
 5 
 6     . = 0x100;
 7     .text : AT(0x7C00)
 8     {
 9         *(.text)
10         *(.gnu.linkonce.t*)
11     }
12     .ctors :
13     {
14       start_ctors = .; _start_ctors = .; __start_ctors = .;
15       *(.ctor*)
16       end_ctors = .; _end_ctors = .; __end_ctors = .;
17 /*      . = ALIGN(0x1000); */
18      }
19     .dtors :
20     {
21       start_dtors = .; _start_dtors = .; __start_dtors = .;
22       *(.dtor*)
23       end_dtors = .; _end_dtors = .; __end_dtors = .;
24       . = ALIGN(0x1000);
25      }
26 
27     .rodata :
28     {
29 
30 
31         *(.rodata*)
32         *(.gnu.linkonce.r*)
33     }
34 
35     .data :
36     {
37         *(.data)
38         *(.gnu.linkonce.d*)
39     }
40 
41     .bss :
42     {
43         sbss = .;
44         *(COMMON)
45         *(.bss)
46         *(.gnu.linkonce.b*)
47         ebss = .;
48     }
49 
50     /DISCARD/ :
51     {
52         *(.comment)
53         *(.eh_frame) /* discard this, unless you are
                implementing runtime support for C++ exceptions. */
54     }
55 }

g++  -static -m32  -g -Wall -Wextra -nostdlib -fno-builtin -nostartfiles -nodefaultlibs -fno-exceptions -fno-rtti -fno-stack-protector  -c -o io.o io.cpp
ld -m elf_i386 -static -Tcpp.ld -nostdlib -M -o cppb.elf cppb.o io.o > cb.elf.map
objcopy -R .pdr -R .comment -R.note -S -O binary cppb.elf cppb.bin

ref: 程式設計師的自我修養: 連結、載入、程式庫

沒有留言:

張貼留言

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

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