1、問題的提出
函式是 c語言中的重要概念。利用好函式能夠充分利用系統庫的功能寫出模組獨立、易於維護和修改的程式。函式並不是 c 語言獨有的概念,其他語言中的方法、過程等本質上都是函式。可見函式在教學中的重要意義。在教學中一般採用畫簡單的堆疊圖的方式描述函式呼叫,但由於學生對堆疊沒有直觀認識,難以深入理解,因此教學效果往往並不理想,從而限制了對模組化程式設計思想的理解和應用。
2、解決方法
在《微機原理》 課程介紹了堆疊、組合語言等必要的相關知識之後,通過在高階語言開發環境下反彙編c 語言程式**,使得學生通過分析彙編**來理解函式呼叫中的堆疊變化,可以在實踐中理解高階語言和低階語言的底層對映關係,理解函式呼叫的實質。本文通過在 visual c++6.0 下反彙編乙個 32 位 c語言程式的部分**來解析解釋函式呼叫的具體過程。
3、函式呼叫過程
函式呼叫過程主要由引數傳遞、位址跳轉、區域性變數分配和賦初值、執行函式體,結果返回等幾個步驟組成[1]。
3.1、引數傳遞及函式跳轉
引數由實參傳遞給形參。在底層實現上,即是實參按照函式呼叫規定壓入堆疊。引數傳遞完成後就通過call指令由當前程式跳轉到子程式處。
3.2、區域性變數分配並賦值
函 數的「」被解釋為函式體已經執行完。遇到「}」時,會將堆疊中的區域性變數、程式中壓入堆疊的暫存器的值全部彈出,將之前 call指令執行時壓入堆疊的函式返回位址彈到指令指標暫存器 eip,從而返回到主調函式。
3.7、堆疊平衡
堆疊平衡指的是將函式呼叫前壓入堆疊的引數彈出堆疊,使堆疊恢復到其呼叫前的狀態[3]。由於函式呼叫完成後,引數就是無用的資料了,因此需要將其移出堆疊。
在 c語言中不需要進行堆疊平衡。而在彙編層面上卻根據呼叫約定來確定由主調函式或是被調函式完成堆疊平衡。
c語言函式呼叫堆疊常見形式如圖 1 所示[4]:
引數由主調函式壓入堆疊,call 指令將函式返回位址入棧。進入子函式後,需要儲存 ebp 原值、分配區域性變數空間、儲存暫存器初始值。函式內通過「ebp-位移量」方式訪問區域性變數,通過「ebp+位移量」方式訪問引數[5]。
每發生一次函式呼叫,就會在堆疊中建立乙個棧幀,棧幀在函式呼叫後釋放。但是系統的堆疊資源有限,因此如果函式呼叫(如遞迴呼叫)層數過多,則可能發生堆疊溢位錯誤。
4.反彙編**分析
以下將函式 function 的呼叫相關**在visualc++6.0 debug模式反彙編,通過對彙編**的分析揭示函式呼叫的關鍵點和細節。完整的 c語言程式**如圖 2 所示:
function(i,&j)語句的反彙編**如圖 3 所示:
先 找到主函式中的區域性變數 i,j(其在堆疊中位置為 ebp- 8和 ebp- 4),將其壓入堆疊。visual c/c++的編譯器對 c 語言程式的預設函式約定為 _cdecl[6]。此引數入棧約定為自右向左,並且對函式名前加「_」修飾符。先將 j 的位址壓入堆疊,後將 i 的值壓入堆
棧。通過 call 指令呼叫函式。從 call 指令可見 fuction函式編譯後加了「_」修飾符。call 指令執行時自動將函式的返回位址入棧,之後轉到 function 定義處開始執行此函式。
對funciton函式的「」時的操作如圖 6 所示:
將暫存器 edi、esi、ebx 恢復原值;將 esp 調回到 ebp 處;將 ebp原值彈出。此時 esp 指向函式返回位址。執行出棧指令,將函式的返回位址彈入 eip 暫存器返回到主調函式。此時堆疊中只殘留有呼叫函式時壓入的引數還沒有清理。
主調函式中的堆疊平衡語句如圖 7 所示:
根據 _cdecl 約定,需要由主調函式完成堆疊平衡。主調函式根據壓入堆疊的引數的數目 2 和引數大小,利用指令 add esp,8 將引數全部彈出。此時堆疊就恢復到其呼叫前的狀態。乙個完整的函式呼叫過程完成。
利用反彙編手段解析C語言函式
利用反彙編手段解析c語言函式 通過在 visual c 6.0 下反彙編乙個 32 位 c語言程式的部分 來解析解釋函式呼叫的具體過程。函式呼叫過程 函式呼叫過程主要由引數傳遞 位址跳轉 區域性變數分配和賦初值 執行函式體,結果返回等幾個步驟組成。引數傳遞及函式跳轉 引數由實參傳遞給形參。在底層實現...
C語言反彙編
這裡使用的是keil4軟體,將編寫的c語言程式彙編成組合語言。這裡只用最簡單的c語言做了一下參考,所舉的例子是最簡單的,只能用於了解一下彙編的表達方式。如圖所示,條件判斷語句的彙編語句表達是賦值後與進行異或比較,再判斷是否進行跳轉。將立即數03賦值給累加器a,然後將累加器a的值與立即數05進行異或 ...
C 虛函式呼叫的反彙編解析
虛函式的呼叫如何能實現其 虛 作為c 多型的表現手段,估計很多人對其實現機制感興趣。大約一般的教科書就說到這個c 強大機制的時候,就是教大家怎麼用,何時用,而不會去 一下這個虛函式的真正實現細節。當然,因為不同的編譯器廠家,可能對虛函式有自己的實現,呵呵,這就算是虛函式對於編譯器的 多型 了 作為編...