the 1st edition: 20120826
the 2nd edition: 20150308
請先參考以下文章, 了解整個來龍去脈:
- 作業系統之前的程式 (1) - c++ 篇
- 作業系統之前的程式 (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 開始:
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 會不同) 的位址:
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
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 帳號。