環境:vs2017 community,win32 debug,專案屬性,常規,全程式優化,無全程式優化
來看反彙編:#include
void hello()
int main()
通常我們都會在這裡f10進入函式,今天我們選擇f11單步執行如下:
注意,程式跳轉到了乙個位置,從反彙編來看,此區域是乙個比較大的跳轉表,而且這個跳轉表是在exe 模組內部的,其上下的跳轉表對應的都是***crt***x函式,即執行時函式,由此可見,這個表跳轉是函式內部的乙個跳轉表。
《老碼識途》作者給出的解釋是:pe (windows 平台下)的生成通常包括兩步:編譯,鏈結。編譯針對的是.cpp/.c 檔案,產物是.obj 檔案。當源**存在多個模組(.cpp/.c檔案)時,模組之間(.cpp/.c檔案)可能會有函式呼叫關係,為了方便的引用模組之間的函式,每個obj 檔案都有兩個列表,乙個列表,包含了本模組的所有函式,另乙個列表,包含了本模組所引用的尚未確定的函式。鏈結前,obj檔案中的函式呼叫是通過call offset + jmp 位址來進行函式呼叫的,如果所呼叫的函式尚未確定,此時call(e8 offset) 後面的位址為0。鏈結時,鏈結器一次解決所有模組中尚未確定的模組的位址,並將e8指令後的偏移修正為正確的值。
構建如下的dll:
// dllmain.cpp : 定義 dll 應用程式的入口點。
上圖分別是dll 內部自己呼叫hello 函式,與exe 呼叫匯入的hello 函式的過程。我們可以看到,當dll內部,即pe 呼叫內部的函式時將會使用e8+偏移指令,然後跳轉到乙個jmp 指令,jmp 跳轉到真正的位置執行我們的函式。
當exe 呼叫匯入的函式時,首先通過乙個ff 15 [位址]指令,跳轉到匯入表中指定的位址,然後再執行jmp 指令跳轉到真正的函式實現的位址。通過對比我們發現,該jmp 指令的位址是相同的,且該jmp 指令在dll 模組中。
由此我們可以總結得到函式呼叫的過程為:
ff 55 ec(取反加一即為-14) call
dword
ptr[ebp-14h]
同樣是通過讀取記憶體來進行第一次的跳轉,而這個記憶體為棧記憶體
同上。
同上
函式呼叫與系統呼叫的區別
函式庫呼叫 系統呼叫 在所有的ansi c編譯器版本中,c庫函式是相同 的各個作業系統的系統呼叫是不同 的它呼叫函式庫 中的一段程式 或函式 它呼叫系統核心 的服務與使用者程式 相聯絡是作業系統 的乙個入口點 在使用者位址空間執行 在核心位址空間執行 它的執行時間屬於 使用者時間 它的執行時間屬於 ...
系統呼叫與庫函式呼叫
linux下對檔案操作有兩種方式 系統呼叫 system call 和庫函式呼叫 library functions 系統呼叫實際上就是指最底層的乙個呼叫,在linux程式設計裡面就是底層呼叫的意思。面向的是硬體。而庫函式呼叫則面向的是應用開發的,相當於應用程式的api,採用這樣的方式有很多種原因,...
函式呼叫與遞迴
遞迴,就是遞迴的呼叫自己,直到滿足結束條件並返回。這是大部分材料對遞迴的定義,從程式上看也符合一般的觀感。但是,不了解函式的呼叫過程,對這句話的理解還是會模糊不清的。函式是怎麼呼叫自己,又是如何返回的?下面是常用來說明遞迴呼叫的例子 遞迴求n的階乘n int factorial int n 遞迴是程...