2016-07-07 14 views
0

我正在学习如何在MASM32程序工作,所以我写的过程,写一个数字:SIGSEGV,分割过错而做“RET”

.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”成功,但尝试后做“ret”有个问题:“程序收到信号SIGSEGV,分段错误。”。我该怎么办?

+0

你有不平衡的堆栈。你想删除你推送的'号码'。 – Jester

回答

0

由于未能正确清理堆栈,导致堆栈不平衡。

在你的代码文件的顶部,你有这样的指令:

.model flat, stdcall 

的重要组成部分,是stdcall指令,指定你的函数将使用调用约定。这是Windows程序最常用的调用约定,它与Windows API使用的是相同的。 stdcall调用约定有两个重要特性:

  1. 将参数从右到左推入堆栈。
  2. 被调用者负责在堆栈返回之前清理堆栈。

第一个功能与其他常用调用约定cdecl相同,但第二个功能完全相反。这是你在这种情况下出错的原因。 (实际上,你的代码根本不清理堆栈,所以无论调用约定它都会被中断!)

基本上,当你使用stdcall调用约定时,你将使用ret instruction这个版本立即作为一个论点。该参数指定返回时从堆栈弹出的字节数。

在这种情况下,你有一个说法,字大小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即可返回控制权。