【问题标题】:SIGSEGV, Segmentation fault while doing "ret"SIGSEGV,执行“ret”时出现分段错误
【发布时间】:2016-07-07 12:40:23
【问题描述】:

我正在学习如何使用 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”,但尝试执行“ret”后出现问题:“程序收到信号SIGSEGV,分段错误。”。我该怎么办?

【问题讨论】:

  • 您的堆栈不平衡。你想删除你推送的number

标签: assembly segmentation-fault masm32


【解决方案1】:

您没有正确清理堆栈,导致堆栈不平衡。

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

.model flat, stdcall

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

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

第一个特性与另一个常见的调用约定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 的控制权。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-04
    • 1970-01-01
    • 1970-01-01
    • 2021-10-24
    • 1970-01-01
    相关资源
    最近更新 更多