iOS由MacOS系統(tǒng)修改而來(lái),所以很多機(jī)制是相同的,與Android-Linux相比相似性更高。iOS符號(hào)分為自動(dòng)non-lazy和lazy綁定符號(hào),non-lazy符號(hào)位于Mach-O文件__DATA Segment 的__nl_symbol_ptr section,lazy符號(hào)位于__DATA Segment 的__la_symbol_ptr section。對(duì)于non-lazy的符號(hào)綁定時(shí)機(jī)為動(dòng)態(tài)庫(kù)加載(load),lazy符號(hào)的綁定時(shí)機(jī)則與Linux相同即函數(shù)第一次被調(diào)用。
測(cè)試代碼
#include <stdio.h>
int main(int argc, const char * argv[]) {
// insert code here...
printf("Hello, World!\n");
printf("Hello World Again!\n");
return 0;
}
lldb 調(diào)試
+34為調(diào)用第一個(gè)printf函數(shù),+51第二次調(diào)用printf函數(shù)。
二進(jìn)制文件DATA段有兩個(gè)section
不用展開(kāi)也應(yīng)該能猜到是哪兩個(gè)sction,section[0]為_(kāi)_nl_symbol_ptr section[1]為_(kāi)_la_symbol_ptr 。回到匯編代碼,printf函數(shù)的地址無(wú)論第一次還是第二次都是0x100000f66,這個(gè)地址來(lái)自哪呢?
由上圖可知,0x100000f66值為_(kāi)_TEXT Segment中的__stub section。
該section的作用解釋如下
- section (__TEXT,__stubs) - section contains stubs with prefix imp___stubs__. That stubs are used in the code of __text section to compile procedures with external dependencies, such as system NSLog. dyld (dynamic linker) will replace such stubs on runtime with actual place in dynamic library.
大意就是該section保存的是編譯過(guò)程中的外部依賴,在運(yùn)行時(shí)動(dòng)態(tài)鏈接器dyld將其替換為實(shí)際位置 PS:靈魂翻譯
call下斷,si進(jìn)去
程序jmpq 0x0000000100000f7c,在__la_symbol_ptr section address中符號(hào)的地址為0x0000000100001010
繼續(xù)調(diào)試
0x0000000100000f7c僅將0x0壓棧后就jmp回0x100000f6c,printf函數(shù)的地址查詢最終是通過(guò)dyld_stub_binder函數(shù)實(shí)現(xiàn)。dyld_stub_binder中符號(hào)查找原理可以參考fishhook
看了以上匯編是否覺(jué)得與Linux PLT頗有幾分相似?
0x0同樣為索引
第二次調(diào)用printf
綁定結(jié)束,從此可以直接調(diào)用相應(yīng)函數(shù)
參考: