2010年5月3日 星期一

[組語] PROC & ENDP

; Caspar-comment - PROC用來定義程序,以ENDP表示結束
; Caspar-comment - 若sub function與main function在同一段Code則使用NEAR, 主程式的Stack只會存入ip
; Caspar-comment - 若sub function與main function不在同一段Code則使用FAR, 主程式的Stack會存入cs, ip的值

FooStart         PROC NEAR C PUBLIC


CALL 指令

用來呼叫副程式的指令,語法是

CALL 副程式名

RET 指令

RET 指令是在副程式中返回主程式的指令,其語法是:

RET n
RETN n
RETF n

n 是位元組數,此位元組數表示自副程式返回時還要再使 SP 加上幾個位元組。常用於高階語言呼叫副程式,見第 31 章。RETN、RETF 見 PROC/ENDP 假指令的說明。
PROC/ENDP 假指令

PROC 並非 80x86 指令而是假指令,它是用來定義副程式,它指出副程式由此開始,必須和 EDNP 搭配使用,否則組譯器會出錯。語法是:

標號名 proc [near/far]
;副程式碼
ret
標號名 endp

標號名就是這個副程式的名稱,例如當 CPU 執行到

CALL my_subroutine

指令時,就會跳到名為 my_subroutne 的副程式執行。

若 PROC 後接 near 表示副程式與主程式在同一區段內,稱為近程呼叫;若接 far,表示副程式與主程式在不同區段內,稱為遠程呼叫。若省略 near 和 far,組譯器能自動判斷副程式與主程式是否在同一區段內。近程呼叫或遠程呼叫會影響返回位址的大小。很明顯的,近程呼叫,只要把下一指令的偏移位址推入堆疊即可而偏移位址只有一個字組的大小;如果是遠程呼叫,就要把區段位址及偏移位址,共兩個字組推入堆疊。

這也影響到返回時要自堆疊取出一個或兩個字組,因此分別用 RETN、RETF 來表示。但是如果用 RET,也沒關係,組譯器也能自動判斷。


可多參考INTEL和AMD在CPU指令手册

下面有一個例子
;------------------------------------------------------------------------------
; VOID
; IoOutput32 (
; IN UINT16 Port,
; IN UINT32 Data
; )
;------------------------------------------------------------------------------
IoOutput32 PROC PUBLIC Port:UINT16, Data:UINT32
pushad
mov eax, Data
mov dx, Port
out dx, eax
popad
ret
IoOutput32 ENDP

參考資料:
asm - 副程式

沒有留言: