"付出努力的過程也許是舉步維艱的,但必須是開心和充實的。“
----火星人
在挖掘工程代碼的過程中,僅僅游走在header文件和源代碼文件中往往是意猶未盡的感覺,尤其在實際環境中很難確定某一版本的開源代碼真的就是當前系統運行的代碼,反正無論怎樣,對庫文件的匯編追蹤都是必不可少的。
匯編代碼中的symbol追蹤是非常重要的一環,一旦要對庫函數做實驗,編譯測試代碼,通過binary tool分析目標代碼去hunt down真正的庫函數細節!
此篇就是介紹在Mac OS X下這個過程的操作,let's do it.!
最近Mars在研究關於NaN的問題(Orz,寫這篇的時候NaN的那篇還不到50%完成度,崩潰中......),那就用相關的代碼來介紹一下吧!假設現在寫下了下面個這個小羔羊程序:
#include <math.h> int main() { double d0 = nan("0xfff0000000001230"); return 0; }
這個程序的目標是追蹤一下nan這個libc標准函數的實現,在庫header里面大家是看不到他嘀~,因為他的實現代碼是編譯代碼。
gcc -g -o nan nan.c
看一下編譯后匯編代碼的主體,因為沒有-O選項,所以能看到沒有任何優化的原貌:
_main: Leh_func_begin1: pushq %rbp Ltmp0: movq %rsp, %rbp Ltmp1: subq $16, %rsp Ltmp2: leaq L_.str(%rip), %rax movq %rax, %rdi callq _nan movsd %xmm0, -16(%rbp) movl $0, -8(%rbp) movl -8(%rbp), %eax movl %eax, -4(%rbp) movl -4(%rbp), %eax addq $16, %rsp popq %rbp ret Leh_func_end1:
從匯編碼中看到了"callq _nan",毫無挑戰的行蹤敗露。下一步常規的手段可能會這樣做:
otool -L nan
但這樣的結果如下:
但事實上在/usr/lib/libSystem.B.dylib中根本不存在_nan的代碼,只需要:
nm -a /usr/lib/libSystem.B.dylib | grep _nan
就可以知道:
完全沒有,就算是存在符號連接也會被nm -a輸出來的。
為什么會出現這么奇怪的情況,明明有外部符號,但otool輸出的庫缺沒有這個外部符號的信息?這個問題目前還沒找到答案,當另一種追蹤符號的方法反而被腦補出來了。
因為下一步要gdb調試,所以帶上-g,添加調試符號信息。OK~let's gdb it.
下面分別截圖gdb的整個過程:
1)啟動gdb看看代碼
2)設置斷點讓程序運行,至於運行到哪里似乎沒什么所謂(因為在實驗中,把nan的調用嵌入到三重函數嵌套調用中,把斷點設置在最外層函數調用之前,也同樣可以),因為程序一旦開始執行,就會加載動態鏈接庫的符號。
3)秘密武器出來~
在最后一步,通過info symbol nan就把這個未定義的外部符號最終歸屬給找出來了!!稍微檢驗一下:
nm -a /usr/lib/system/libmathCommon.A.dylib | grep "_nan"
搞定~找到~接下來就看_nan的代碼吧!!
otool -p "_nan" -tV /usr/lib/system/libmathCommon.A.dylib
好啦,到這里已經完成對symbol追蹤過程的闡述,也故意列出一些otool和nm的使用方法,希望大家受樂啦~畢竟Mac OS X下二進制文件的處理真不太方便,沒有了objdump和readelf,雖然可以安裝傳說中的binutils,但一直沒裝上,Mars土鱉了。