在之前的文章中,我們已經簡單的了解了64位的一些引數的知識,下面我們從不同的情況對64位的堆疊與函式做詳細的講解。
首先,對於64位的函式,他的引數並不都是以push壓棧的方式進行傳遞的,他的前4個引數分別通過rcx,rdx,r8,r9這幾個暫存器進行傳遞(如圖)
從圖中的函式可以發現,64位的函式是不會對引數進行push的,而是將前4個引數傳遞給了rcx-r9這4個暫存器。從引數視窗,可以輕易的看到這些引數的數值。
那麼在這種情況下如何分辨具體用到了哪些引數呢?
首先在函式呼叫處進行觀察,一般來說,函式的引數在呼叫處附近會傳遞給rcx-r9這4個暫存器,並在函式內部進行呼叫。所以觀察在函式呼叫前,看哪些暫存器被進行賦值。
其次在被呼叫函式頭部進行觀察,看4個暫存器中的哪些在函式中對其他記憶體進行賦值(如圖)
圖中的rdx,r8,r9都在函式頭部被使用,而rcx則在被使用前被其他位址進行了賦值,所以說這個函式只需要傳遞rdx-r9三個引數即可,而rcx並不會影響該函式的呼叫。當然,這種情況也是非常少見的,通常rcx的使用率會遠高於其他的三個暫存器。
以上是在函式引數不多於4個的情況下,函式的引數傳遞情況。那麼當函式的引數超過4個以後,引數又如何進行傳遞呢?(如圖)
圖中是某尋路函式,在函式被呼叫前,我們可以看到出了rcx-r9暫存器意外,還有rsp+20,rsp+28,......,rsp+40被賦值,這些被賦值的堆疊位址,就是函式第四個引數以後的其他的引數。
在rsp+20前面還有20位元組,是作為預留的4個8位元組存在的,有時候會在函式內部用來傳遞rcx-r9這4個引數,而在呼叫函式時通常是無需在意這20位元組的。
當然,64位的函式在單步進入函式內部時也需要push乙個8位元組的返回位址,這一點和32位相同(如圖)
這時的第五個引數則變為了rsp+28,後面的引數位址依次+8,而前面的4個引數不變,依然為rcx-r9。
可以將64為函式的引數傳遞總結為下圖(如圖)
以上為64為函式的引數與堆疊的關係,那麼在函式執行的過程中如果遇到了堆疊位址應該如何分析呢?這裡也分為幾種情況。
引數的傳遞
引數的傳遞相對區域性變數會簡單很多,通常我們只需要將堆疊位址計算到函式頭部,就可以得出具體是由那個引數傳遞的(如圖)
022e1e88處的r14d**於[rbp+148],而rbp+148計算到頭部為rsp+40,在頭部到022e1e88處沒有任何**對這個位址賦值,也就是說明這個位址裡的值是**於上一層傳進來的引數(如圖)
執行到返回後我們可以看到22f1f5b處[rsp+38]被r15b賦值,這也驗證了我們的之前的推測。
區域性變數的傳遞
區域性變數的傳遞也分為很多種,第一種是通過rbp+n的這種方式進行傳遞的,這裡的n可能為正值也可能為負值(如圖)(如圖)
圖中的rax**於[rbp+37],而rbp在頭部**於rax-5f,經過計算,rbp+37的位址在函式頭部為rsp-28,這說明rbp+37其實是乙個區域性變數。於是我們在函式內部進行分析,並得到1e5c57d處的mov qword ptr [rbp + 0x37], rsi
這是最簡單的,也是最常見的區域性變數傳遞。
第二種是區域性變數以引數的形式傳遞到函式中,並在函式中被賦值(如圖)(如圖)
圖中1a497b1處的rcx**於[rsp+70],而rsp+70計算到頭部為rsp+8,看似是**於第乙個引數的,但是並沒有引數向這個位址中傳遞數值,而在頭部下斷發現rsp+8裡也的確沒有被寫入任何數值。這說明[rsp+70]其實是乙個區域性變數。
在1a49797處我們發現rsp+70的位址傳給了rdx,而經過下面這個函式後被賦值,這說明rsp+70做為結構體引數被傳入到了函式中,並且在函式內部被進行賦值。以下是賦值處的**(如圖)
以上就是引數和區域性變數常見的傳遞方式。在64位**中,區域性變數和引數分析起來非常簡單,因為大部分的函式都不會對堆疊造成影響。但是引數的分析則麻煩一些,因為引數的傳遞一般不會用到push,而好處則是當引數個數較少的時候,我們不會因為忽視堆疊的變化導致堆疊不平衡,進而讓程式崩潰。
python 函式引數與區域性變數
形參變數只有在被呼叫時才分配記憶體單元,在呼叫結束時,即刻釋放所分配的記憶體單元。因此,形參只在函式內部有效。函式呼叫結束返回主呼叫函式後則不能再使用該形參變數 實參可以是常量 變數 表示式 函式等,無論實參是何種型別的量,在進行函式呼叫時,它們都必須有確定的值,以便把這些值傳送給形參。因此應預先用...
arguments實參集合與區域性變數引數的關係
function fn1 a,b,c fn1 1,2,3 實參 實際傳遞的引數arguments適用場合 當函式的引數個數無法確定的時候function sum return result console.log sum 1,2,3,4,5,386 利用arguments.length檢視實參和形參...
python函式全域性變數與區域性變數
區域性變數 在函式中定義的變數一般只能在該函式內部使用,這些只能在程式的特定部分使用 全域性變數 在乙個檔案頂部定義的變數可以供該檔案中任意函式呼叫 1優先讀取區域性變數,能讀取全域性變數,無法對全域性變數重新賦值 name 全域性變數 def change name name 區域性變數 prin...