Xcode呼叫乙個printf都會進行那些操作

2021-10-23 03:16:33 字數 2518 閱讀 6295

比如這是乙個 arm64 架構下的 macho 檔案。mach 載入器會讀取 macho 檔案中的載入命令(load commands),這些命令決定了如何布局這個程序的記憶體空間。

(這裡需要注意:記憶體位址和 macho 檔案的 offset 是兩個概念,對於 text 和 data 段中的東西,arm64 架構下,可以認為0x100000000 + offset + aslr = 記憶體位址

那麼我們首先看看呼叫 ​printf()​ 的彙編是什麼樣的。

然後在呼叫 ​printf()​ 時打乙個斷點。執行到這個斷點時,我們看到了這樣一行彙編**:

0x10044e694 : bl     0x10044ea78               ; symbol stub for: printf
意思是跳轉到 ​0x10044ea78​ 位址繼續執行,並且這個位址,代表了 printf 函式。0x10044ea78改位址,實際是什麼呢?(記憶體中的位址!)

由於 aslr 技術,我們需要減去 image 的起始位址,才能得到 rebase 之前的位址,用於和 macho 檔案對比。通過 ​image list​ 命令得到各個 image 的起始位址後,我們發現,​0x10044ea78​ 落在起始位址為 ​0x0000000100448000​ 的主二進位制中,二者相減,偏移量為 ​0x6a78。

則記憶體中的0x10044ea78對應 macho的主二進位制檔案中的偏移為????0x6a78位址中(該位址位於text 段 __stubs 節),說明呼叫printf()​ 首先跳轉到了**段的某個位址上。

0000000100006a78        nop

0000000100006a7c ldr x16, #0x15dc

0000000100006a80 br x16

//nop 為空命令

ldr 這一行的意思是,將當前 pc 暫存器中的值,加上 0x15dc,再存到 x16 暫存器中

br 這一行的意思是,跳轉到 x16 暫存器的值指向的位址。

總的來說就是就是跳轉到了x16暫存器的位址中(0000000100006a7c​ + ​0x15dc​ =0x8058

去檢視 0x8058 這個位址,它位於 data 段 __la_symbol_ptr 節。

__la_symbol_ptr節是一系列指標,這些指標指向的,是某乙個指令的位址。

這裡 ​0x8058​ 這個位址中存的是 ​0x100006b08

這個 0x100006b08 是 macho 還未 or 剛剛載入記憶體中時,記憶體中 0x100008058 位址存的值。但是記憶體中的值是可以被改變的。事實上,只有第一次呼叫 printf 的時候,這一步會跳轉到 0x100006b08,之後,這個記憶體會被寫入新的位址,即動態庫中 printf() 函式的位址。???這就是lazy bind。

接下來0x100006b08位於 __text 段 __stub_helper 節,它的彙編指令是:

接下來會跳轉到0x6a84這個位址,這個位址是 __stub_helper 節的開頭。

執行幾個指令後,就回去呼叫 dyld_stub_binder 函式。

dyld_stub_binder 是 dyld 執行 bind 的函式。這個函式執行完後,__la_symbol_ptr 節中的內容,將不再是指向 __stub_helper 節的位址,而是 printf 函式真正的位址。

那麼下次呼叫 printf 函式的時候,就可以直接通過 __la_symbol_ptr,找到真正的 printf 函式位址了。

乙個printf引發的問題

牛客網上的乙個題目 intmain 看起來挺簡單的,牽扯的東西比較多。這是我的思路 printf函式執行的時候,會先把這三個數字壓入棧裡,然後再執行列印。壓入棧的時候按照資料本身的長度來,首先把c和b壓入,並且每乙個都是8個位元組 printf自動轉化為double 然後再壓入a是4個位元組。然後再...

自己實現乙個printf函式

在arm嵌入式開發環境中,串列埠一般使用arm pl011的uart實現,uart的實現原理就是實現了乙個8bits寬度,32深度的fifo,不停的往螢幕輸出乙個byte,乙個byte。這個就是硬體的實現,那麼軟體是怎麼實現列印 高階程式語言中定義的char,short,int,long,float...

vc 中printf的乙個實現

int cdecl messageboxprintf tchar szcaption,tchar szformat,int winapi winmain in hinstance hinstance,in opt hinstance hprevinstance,in opt lpstr lpcmdl...