C語言動態函式呼叫

2021-07-25 05:06:20 字數 1158 閱讀 7719

在遠端呼叫中,伺服器在收到請求後,需要通過查符號的手段,獲取函式指標,然後呼叫客戶端請求的函式。然而,不同函式引數個數、型別皆不相同,函式指標在定義時就需要明確型別,因此,沒有一種定義,可以滿足所有函式的呼叫。

最先想到的是參考目前專案中控制台手動輸入函式時的實現方式,即tpf庫的實現。tpf庫在查詢符號時,使用乙個u32 *型別的變數充當函式指標(通過強制型別轉換)。在呼叫時,將此指標強制轉換為乙個包含32個s32並且返回值是s32的函式指標。如果使用者傳遞的引數不足32個,則後面的全部補0。也就是說,tplf的實現完全不考慮呼叫的函式原型是什麼樣,統一以乙個原型去呼叫目標函式。

初看這段**,函式指標型別與真正的函式定義不匹配,我個人認為應該是有問題的。比較奇怪的是,在實際測試中,發現這樣並沒有發生引數傳遞錯誤、函式內區域性變數被覆蓋等問題。

通過反彙編分析**,得到了以下結論:

 呼叫時,根據函式指標的型別,將引數從右至左壓入堆疊,堆疊位址逐步減小。

 在被調函式中,先儲存呼叫者函式的棧底位址(push ebp),讓後將ebp指標移動到被呼叫函式的棧底(mov %esp,%ebp)。即保證ebp指標永遠指向當前函式的棧底。

如圖所示:

在上圖可以看出,通過ebp來區分呼叫者與被呼叫者的棧幀,使用esp來區分當前函式的區域性變數,以及下乙個呼叫函式的引數列表。在被呼叫函式中,使用ebp+引數偏移位址,去取呼叫者傳遞的引數。由於呼叫者在傳遞引數時,從右至左壓入堆疊,因此,在左邊的引數距離ebp較近。即使多傳遞了多餘的引數,只不過多占用了一些堆疊而已,並不會對函式呼叫產生影響。

另外,我對函式需要傳遞char或者short型別的原型同樣做了實驗。通過分析彙編**發現,這兩種型別在編譯之後依然按照4位元組占用堆疊空間,因此不存在問題(大端、小端系統均沒有問題)。

通過以上分析,tpf雖然使用了比較詭異的呼叫方式,但是針對引數個數小於32個的情況,均不會出現問題。如果引數大於32個,則會使得被呼叫函式訪問到非法的引數棧(因為引數棧固定為32個4位元組)。

在網上也找了一些其他的開源**實現,例如:dyncall、libffi等。這一類**實現原理,需要使用者呼叫其介面,告知每乙個引數的型別。其實現原理,應該是採用彙編**,根據引數型別,在執行態執行引數入棧操作。其致命缺陷,在於使用者在呼叫時,必須明確引數個數以及每乙個引數型別,無疑增大了使用者api介面的程式設計工作量。

綜合考慮,使用tpf實現c語言動態函式呼叫。

VS C 中呼叫C 動態庫靜態函式

test.cpp 定義控制台應用程式的入口點。include stdafx.h include using debug writelog.dll using namespace writelog1 using namespace std int tmain int argc,tchar argv 說...

靜態函式呼叫

include class point static void init 靜態成員函式 呼叫1 非靜態成員函式和非靜態成員屬於物件的方法和資料,也就是先產生類的物件,然後通過類的物件去引用。void main 呼叫2 靜態成員函式和靜態成員變數屬於類本身,在類載入的時候,即為它們分配了空間,所以可通...

C語言靜態函式不能被其他檔案呼叫

做個c小實驗,向判斷乙個動態庫對外暴露的介面函式能否同時被兩個程式呼叫,實驗結果是可以的。然後試一下把那個介面函式寫成靜態函式再次嘗試,編譯出現報錯。c語言中的static函式 內部函式和外部函式 函式一旦定義後就可被其它函式呼叫。但當乙個源程式由多個原始檔組成時,在乙個原始檔中定義的函式能否被其它...