2014-03-28 65 views
0

考慮下面的代碼:調用函數時會註冊什麼?

ArraySum PROC 
; Receives: ESI points to an array of doublewords, 
; ECX = number of array elements. 
; Returns: EAX = sum 
;----------------------------------------------------- 
    push esi ; save ESI, ECX 
    push ecx 
    mov eax,0 ; set the sum to zero 

L1: 
    add eax,[esi] ; add each integer to sum 
    add esi,4 ; point to next integer 
    loop L1 ; repeat for array size 
    pop ecx ; restore ECX, ESI 
    pop esi 
    ret 
ArraySum ENDP 

爲什麼編碼器決定拯救的ESIECX值是多少? 我的意思是,從某處撥打ArraySum的人必須爲ArraySum「準備」ESIECX

不太具體,我應該在寫函數時保存哪些寄存器?只是我使用的函數沒有任何人知道它的函數外,或者我使用的所有寄存器除了用於返回值的函數外?

+0

這是平臺特定的,但在32位Windows上,我也相信Linux,例程可以垃圾'eax','ecx'和'edx',但必須保留所有其他寄存器值。 –

+0

x86中有太多「標準」可靠地選擇一個。大約20年前有很多工具供應商。你必須參考你所使用的任何編譯器的文檔。這是一個古老的順便說一句,沒有人再生成LOOP。 –

+0

@HansPassant,我正在閱讀的文本中的標準(代碼來自哪裏)是否有可能是編碼器必須保留所有通用寄存器以期望返回值? – Quaker

回答

1

在32位x86代碼,所述被調用方保存寄存器(即函數應該保存的那些)是EDIESIEBP,和EBX。您所顯示的功能會在循環內修改ESI,因此需要保存其原始值並在返回之前將其恢復。

ECX調用者保存的寄存器中(即它是由函數的調用者,如果它需要它來維持它的價值),因此目前還不清楚爲什麼你顯示的功能將其保存。也許這個編碼器構成了他/她自己的通話慣例。

請參閱Agner Fog's "Calling conventions" document中的表4。

+0

循環指令修改ECX(如loopz,loopnz和jcxz)。 ECX是計數寄存器,其他幾條指令也對其進行了修改。 – Fred

+0

@Fred:好的。我的觀點是,目前還不清楚爲什麼該功能保留了「ECX」的原始值,因爲它不是必須的(按照IA-32上的「stdcall」或「c​​decl」)。 – Michael

+0

@Michael,我沒有完整的代碼,我只是看到了這個功能,並想知道完全一樣的東西。 – Quaker

相關問題