我正在学习如何使用masm32中的过程,所以我编写了编写数字的程序:
.386
.model flat, stdcall
option casemap : none
include \masm32\include\masm32.inc
include \masm32\include\kernel32.inc
include \masm32\macros\macros.asm
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\kernel32.lib
.data
number dw 397
temp db 10
symbol dw ?
i dw ?
.code
printnumber proc num:WORD
mov ecx, 0
mov ax, num
@@:
mov edx, 0
div temp
mov bh, 0
mov bl, ah
push bx
inc cx
cmp al, 0
mov bl, al
mov ax, bx
jnz @B
mov i, cx
@@:
pop symbol
add symbol, 48
mov ax, symbol
print ADDR symbol
dec i
cmp i, 0
jnz @B
ret
printnumber endp
start:
push number
call printnumber
ret ;here program fails
end start
程序成功打印“397”,但在尝试“退回”后出现问题:“编程接收信号SIGSEGV,分段故障。”。我该怎么办?
答案 0 :(得分:0)
由于无法正确清理堆栈,您无法平衡堆栈。
在代码文件的顶部,您有这个指令:
.model flat, stdcall
重要的部分是stdcall
指令,它指定了函数将使用的调用约定。这是Windows程序最常用的调用约定,它与Windows API使用的约定相同。 stdcall调用约定有两个重要特性:
第一个特征与其他常见调用约定cdecl
相同,但第二个特征正好相反。这是你在这种情况下出错的原因。 (实际上,你的代码根本不会清理堆栈,所以不管调用约定它都会被破坏!)
基本上,当您使用stdcall调用约定时,您将使用立即作为参数的ret
instruction版本。该参数指定返回时从堆栈中弹出的字节数。
在这种情况下,您有一个参数,即WORD大小的number
,因此您将使用ret 2
:
printnumber proc num:WORD
mov ecx, 0
mov ax, num
@@:
mov edx, 0
div temp
mov bh, 0
mov bl, ah
push bx
inc cx
cmp al, 0
mov bl, al
mov ax, bx
jnz @B
mov i, cx
@@:
pop symbol
add symbol, 48
mov ax, symbol
print ADDR symbol
dec i
cmp i, 0
jnz @B
ret 2 ; clean up the stack by popping 2 bytes,
; since 2 bytes were pushed by the caller
printnumber endp
除此之外,我相信使用MASM32的start
入口点标签,您必须调用ExitProcess
将控制权返回给Windows。 All the MASM32 samples我见过do it this way:
start:
push number
call printnumber
invoke ExitProcess, 0
end start
但我可能错了。我实际上并没有使用MASM32 SDK。通常,您的入口点将是一个cdecl函数,它只会返回ret
的控件。