如果一個函式需要傳遞大量的引數,顯然暫存器是不夠用的,應該如何解決?愛達人程式設計達人2018-08-27 08:38:34

我們無論學習什麼語言,都離不開函式、引數、引數傳遞、函式呼叫、返回值等這幾個步驟。

我們在編寫一個彙編函式時,用暫存器傳參的方式,要提前約定好參與函式功能的暫存器,將引數存入函式約定好的暫存器中,在進行運算。

那麼問題來了,我們知道的暫存器也就那麼幾十個,如果一個函式需要傳遞大量的引數,顯然暫存器是不夠用的,就需要用到堆疊傳參的方式去解決。

【堆疊傳參的方式】

堆疊傳參看到這幾個字肯定能想到將引數儲存在堆疊中。那我們該怎麼用哪?同樣用例題介紹堆疊傳參的方式。

例:編寫一個函式,實現任意五個整數相加。

分析:需要將5個引數儲存到堆疊中,用CALL指令呼叫函式。

第一步:在DTDebug。exe軟體中開啟飛鴿軟體,如圖2-13-1所示。

如果一個函式需要傳遞大量的引數,顯然暫存器是不夠用的,應該如何解決?

第二步:將5個整數壓入堆疊,輸入以下指令,如圖2-13-2所示。

PUSH 1

PUSH 2

PUSH 3

PUSH 4

PUSH 5

如果一個函式需要傳遞大量的引數,顯然暫存器是不夠用的,應該如何解決?

第三步:依次按F8將引數壓入堆疊中,如圖2-13-3所示。

如果一個函式需要傳遞大量的引數,顯然暫存器是不夠用的,應該如何解決?

按F8執行完看到,堆疊中已經壓入我們傳遞的引數。用CALL呼叫函式,我們怎麼編寫這個函式哪?

我們的常用指令不允許兩邊都為記憶體,所以我們透過ESP棧頂指標來運算。

如果這麼寫:MOV EAX,DWORD PTR DS:[ESP],那麼EAX裡的值是什麼?

我們編寫完引數後,呼叫CALL,會將CALL下一行的指令地址傳入堆疊,這個時候ESP的值就是CALL函式地址,堆疊的變化如圖2-13-4:

如果一個函式需要傳遞大量的引數,顯然暫存器是不夠用的,應該如何解決?

圖2-13-4 堆疊圖

第三步:編寫函式,輸入以下指令,如圖2-13-5所示。

這5個引數依次是:ESP+0x14、ESP+0x10、ESP+0xC、ESP+0x8、ESP+0x4

所以我們的函式可以這樣編寫:

MOV EAX,DWORD PTR DS:[ESP+0x14]

ADD EAX,DWORD PTR DS:[ESP+0x10]

ADD EAX,DWORD PTR DS:[ESP+0xC]

ADD EAX,DWORD PTR DS:[ESP+0x8]

ADD EAX,DWORD PTR DS:[ESP+0x4]

RETN

如果一個函式需要傳遞大量的引數,顯然暫存器是不夠用的,應該如何解決?

第四步:使用CALL呼叫函式,輸入CALL 0x77068E4D,如圖2-13-6所示。

如果一個函式需要傳遞大量的引數,顯然暫存器是不夠用的,應該如何解決?

第五步:按F7觀察堆疊視窗資料變化,如圖2-13-7所示。

如果一個函式需要傳遞大量的引數,顯然暫存器是不夠用的,應該如何解決?

圖2-13-7中,執行完CALL指令,並將CALL指令下一行地址壓入堆疊中,當前黑色定位游標在函式體開始的地址,當前ESP是0x0019FFD8,堆疊視窗中的記憶體使用是從高地址向低地址使用的,所以ESP+14是引數的開始。我們可以雙擊堆疊視窗中的記憶體地址,如圖2-13-8所示。

如果一個函式需要傳遞大量的引數,顯然暫存器是不夠用的,應該如何解決?

第六步:把EAX暫存器的資料變為0x00000000,依次按F8,檢視結果是否正確,如圖2-13-9所示。

如果一個函式需要傳遞大量的引數,顯然暫存器是不夠用的,應該如何解決?

1+2+3+4+5=15,轉化成16進製為F。看圖2-13-9中,EAX暫存器的值為0x00000000F,說明運算結果正確,證明我們編寫的函式是正確的。

第七步:按F8執行RETN指令,如圖2-13-10所示。

如果一個函式需要傳遞大量的引數,顯然暫存器是不夠用的,應該如何解決?

以上是堆疊傳參的過程,總結:堆疊傳參是將引數壓入堆疊中,函式在運算時透過ESP定址的方式去查詢對應的引數並進行運算。

思考:函式執行完了,可是我們的資料還儲存在堆疊中,該怎麼解決呢?

如果一個函式需要傳遞大量的引數,顯然暫存器是不夠用的,應該如何解決?DaShuaiHou2018-08-28 08:13:01

c語言傳參書可以用堆疊的形式,當然也有其它的形式。比如模擬作業系統給main(int argc ,char argv[])的形式,可以傳很多引數,不限制引數個數,當然,在作業系統內部是有限制為20個。本質是傳遞了一個int型數字和一個指向char指標的指標。

另一種,完全可以透過結構體的形式,傳入結構體或則無型別的指標,在函式內部進行獲取結構體內部資料或者指標強轉獲取資料,可以傳遞很多引數,不限個數,完全多一CPU的暫存器個數。其本質也是傳遞的記憶體地址,即指標。32位CPU就是一個int長度的數字而已,佔用一個暫存器,比如r0。

如果一個函式需要傳遞大量的引數,顯然暫存器是不夠用的,應該如何解決?LucklnCaffe2019-03-16 13:40:56

如果太多引數,最好修改設計。實在不行c語言只能用全域性變數來處理了。

如果一個函式需要傳遞大量的引數,顯然暫存器是不夠用的,應該如何解決?味冷2019-03-19 05:30:36

暫存器傳引數主要是少量速度要求高的引數

實際比較多的引數是透過堆疊傳遞的,call指令前要把需要的引數壓棧

如果是比較大的連續的資料結構,就不要整個資料結構壓棧了,把指標壓棧傳遞過去就行了