Win32ASM学习[20]:子程序
關(guān)于函數(shù)調(diào)用約定?:函數(shù)調(diào)用約定
這是以前的一個(gè)求和函數(shù)的例子
----------------------------------------------------------------------------------------------------------------
.386
.model flat, stdcall
include??? windows.inc
include??? kernel32.inc
include??? masm32.inc
include??? debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib
.code
sum proc v1:dword, v2:dword, v3:dword
??? mov eax, v1
??? add eax, v2
??? add eax, v3
??? ret
sum endp
;
main proc
??? invoke sum, 11, 22, 33
??? PrintDec eax; 66
??? ret
main endp
end main
----------------------------------------------------------------------------------------------------------------
把上面的例子改為用寄存器傳遞參數(shù):
----------------------------------------------------------------------------------------------------------------
.386
.model flat, stdcall
include??? windows.inc
include??? kernel32.inc
include??? masm32.inc
include??? debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib
.code
sum proc
??? add eax, ecx
??? add eax, edx
??? ret
sum endp
;
main proc
??? mov eax, 11
??? mov ecx, 22
??? mov edx, 33
??? invoke sum
??? PrintDec eax; 66
??? ret
main endp
end main
----------------------------------------------------------------------------------------------------------------
如果調(diào)用的函數(shù)在之后實(shí)現(xiàn), 須用 PROTO 提前聲明:
----------------------------------------------------------------------------------------------------------------
.386
.model flat, stdcall
include??? windows.inc
include??? kernel32.inc
include??? masm32.inc
include??? debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib
;sum proto v1:dword, v2:dword, v3:dword
sum proto :dword, :dword, :dword ;函數(shù)聲明的主要是參數(shù)類型, 一般省略參數(shù)名
.code
main proc
??? invoke sum, 11, 22, 33 ;現(xiàn)在調(diào)用的是之后的函數(shù)
??? PrintDec eax; 66
??? ret
main endp
;
sum proc v1, v2, v3
??? mov eax, v1
??? add eax, v2
??? add eax, v3
??? ret
sum endp
end main
----------------------------------------------------------------------------------------------------------------
測試 StdCall 模式下的參數(shù)壓棧順序:
----------------------------------------------------------------------------------------------------------------
?子程序可以指定語言模式(StaCall、C、SysCall、Basic、Fortran、Pascal);
如果不指定則默認(rèn)使用在 .model 中指定的語言模式.
StaCall、C、SysCall 是從右到左壓棧參數(shù);
Basic、Fortran、Pascal 是從左到右壓棧參數(shù).
----------------------------------------------------------------------------------------------------------------
.386
.model flat, stdcall
include??? windows.inc
include??? kernel32.inc
include??? masm32.inc
include??? debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib
.code
sum proc stdcall v1, v2, v3
??? ;查看參數(shù)壓棧順序(StdCall 是從右到左 push)
??? mov edx, [ebp+16]
??? PrintHex edx????? ;33
???
??? mov edx, [ebp+12]
??? PrintHex edx????? ;22
???
??? mov edx, [ebp+8]
??? PrintHex edx????? ;11
???
??? PrintLine
???
??? ;下面求和代碼
??? mov eax, v1
??? add eax, v2
??? add eax, v3
??? ret
sum endp
;
main proc
??? invoke sum, 11h, 22h, 33h
??? PrintDec eax; 66
??? ret
main endp
end main
----------------------------------------------------------------------------------------------------------------
測試 Pascal 模式下的參數(shù)壓棧順序:
----------------------------------------------------------------------------------------------------------------
這是和上面的對比練習(xí), 它們的壓棧參數(shù)的順序是反的.
其中的 EBX+8 是最后壓棧參數(shù)(DWORD)的地址, 同樣 EBX 向上偏移 12、16 就分別是另外兩個(gè)參數(shù)的地址.
地址 EBX+4 是 RET 將要返回的地址.
為什么參數(shù)不是在 EBX 的下偏移? 因?yàn)槭窍葔簵?shù)在調(diào)用函數(shù).
----------------------------------------------------------------------------------------------------------------
.386
.model flat, stdcall
include??? windows.inc
include??? kernel32.inc
include??? masm32.inc
include??? debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib
.code
sum proc pascal v1, v2, v3
??? ;查看參數(shù)壓棧順序(pascal 是從左到右 push)
??? mov edx, [ebp+16]
??? PrintHex edx????? ;11
???
??? mov edx, [ebp+12]
??? PrintHex edx????? ;22
???
??? mov edx, [ebp+8]
??? PrintHex edx????? ;33
???
??? PrintLine
???
??? ;下面求和代碼
??? mov eax, v1
??? add eax, v2
??? add eax, v3
??? ret
sum endp
;
main proc
??? invoke sum, 11h, 22h, 33h
??? PrintDec eax; 66
??? ret
main endp
end main
----------------------------------------------------------------------------------------------------------------
如果用 Call 代替 invoke 能更好地理解壓參順序:
----------------------------------------------------------------------------------------------------------------
.386
.model flat, stdcall
include??? windows.inc
include??? kernel32.inc
include??? masm32.inc
include??? debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib
.code
ViewParam proc C v1, v2, v3 ;把這里的 C 換為 pascal 會(huì)有完全不同的結(jié)果
??? PrintDec v1 ;11
??? PrintDec v2 ;22
??? PrintDec v3 ;33
??? ret
ViewParam endp
;
main proc
??? push 33
??? push 22
??? push 11
??? call ViewParam
??? leave ;leave 是上面幾個(gè) push 的反操作, 省了不少 pop
??? ret
main endp
end main
----------------------------------------------------------------------------------------------------------------
子過程使用 uses 保護(hù)寄存器:
----------------------------------------------------------------------------------------------------------------
?所謂保護(hù)就是在子過程執(zhí)行前先壓棧, 執(zhí)行后在出棧.
----------------------------------------------------------------------------------------------------------------
.386
.model flat, stdcall
include??? windows.inc
include??? kernel32.inc
include??? masm32.inc
include??? debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib
.data
??? dwVal dd ?
.code
sum proc stdcall uses eax ecx edx, v1, v2, v3 ;這其中的 stdcall 可省略
??? mov eax, v1
??? mov ecx, v2
??? mov edx, v3
??? add eax, ecx
??? add eax, edx
??? mov dwVal, eax
??? ret
sum endp
;
main proc
??? ;sum 對這三個(gè)寄存器進(jìn)行的保護(hù), 先給些測試值
??? mov eax, 7
??? mov ecx, 8
??? mov edx, 9
???
??? invoke sum, 11, 22, 33
??? PrintDec dwVal ;66
???
??? PrintDec eax ;7
??? PrintDec ecx ;8
??? PrintDec edx ;9
??? ret
main endp
end main
----------------------------------------------------------------------------------------------------------------
使用 uses 不如使用 pushad 和 popad 來得簡潔:
----------------------------------------------------------------------------------------------------------------
.386
.model flat, stdcall
include??? windows.inc
include??? kernel32.inc
include??? masm32.inc
include??? debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib
.data
??? dwVal dd ?
.code
sum proc v1, v2, v3
??? pushad
??? mov eax, v1
??? mov ecx, v2
??? mov edx, v3
??? add eax, ecx
??? add eax, edx
??? mov dwVal, eax
??? popad
??? ret
sum endp
;
main proc
??? mov eax, 7
??? mov ecx, 8
??? mov edx, 9
???
??? invoke sum, 11, 22, 33
??? PrintDec dwVal ;66
???
??? PrintDec eax ;7
??? PrintDec ecx ;8
??? PrintDec edx ;9
??? ret
main endp
end main
----------------------------------------------------------------------------------------------------------------
和子程序密切相關(guān)的有兩個(gè)指令: call 和 ret
call 相當(dāng)于 push+jmp;
ret 相當(dāng)于 pop+jmp;
有些 ret 后面還有個(gè)數(shù)字, 如 ret 8, 這相當(dāng)于 ret 后再 esp+8(這是清理 8 字節(jié)的堆棧).
另外程序可以同 public 和 private 指定是否能跨模塊使用, 默認(rèn)是 public, 極少用到 private.
聲明其他模塊成員的 extrn、extern、public 關(guān)鍵字, 現(xiàn)在用 proto 都可以代替了.
?
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的Win32ASM学习[20]:子程序的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 摩尔庄园手游给艾米赠送礼物任务怎么完成
- 下一篇: Win32ASM学习[21]:宏汇编(1