为什么 fopen 在简单的汇编调用中失败? [警告:长汇编源]

Why fopen fails in simple assembly call? [Warning: long assembly source]

环境,Win 7。使用 NASM、gcc (MINGW)

我有以下非常简单的汇编源代码:

SECTION .data       ; initialized data
    fname:      db  "c:\asmplus\tsources\s1.txt", 0
    fread:      db  "r", 0
    mopf:       db  "[FILE] open: %s", 10, 0

SECTION .text       ; code
    extern _fopen
    extern _printf  

    push        DWORD               fname
    push        DWORD               mopf
    call        _printf
    add         esp,    8           ; clean up stack use

    mov         DWORD [esp],        fname
    mov         DWORD [esp + 4],    fread
    call        _fopen

我得到以下输出:

[FILE] open: c:\asmplus\tsources\s1.txt

... 然后是一个 Windows 对话框,提示应用程序已崩溃。我没有任何可用的调试器,所以我将其分解为最简单的源代码并像这样尝试了它。该文件可用但未打开。我的代码有什么特别的错误吗?

更新
已添加完整代码@Jester 的请求

parse.asm

SECTION .data           ; initialized data
    mend:       db  10, "*** END ***", 10, 0

    mopf:       db  "open_file", 0

    mcll:       db  "[MAIN] call %s: %s", 10, 0
    mret:       db  "[MAIN] ret: %d", 10, 0


SECTION .text use32     ; code
    extern open_file
    extern _printf

    global _main

    _main:
        ;   stash base stack pointer
        push    ebp
        mov     ebp,    esp

        mov     eax,    [ebp + 8]   ; num args
        mov     ebx,    [ebp + 12]  ; address of args (strings)
        mov     ecx,    0           ; init counter register to 0

        .do:
            push    ebp
            push    eax
            push    ecx

            mov     [c],    ecx

            ;   only expect args[1] to contain the file name
            mov     eax,    1
            cmp     eax,    [c]
            jne     .cont
            jmp     .openFile

            .cont:
                pop     ecx
                pop     eax
                pop     ebp

                add     ebx,    4       ; move to next arg
                inc     ecx             ; increment counter

                cmp     ecx,    eax
                jne     .do

        .openFile:
            push    DWORD   [ebx]
            push    DWORD   mopf
            push    DWORD   mcll
            call    _printf
            add     esp,    12

            push    DWORD   [ebx]
            call    open_file           ; should push result to eax

            mov     eax,    [ebp + 8]   ; stash file handle from stack
            mov     [fh],   eax         ; into fh variable

            add     esp,    4           ; clean up stack

            push    DWORD   [fh]
            push    DWORD   mret
            call    _printf
            add     esp,    8           ; clean up stack

        .end:
            push    DWORD   mend
            call    _printf
            ;   restore base stack pointer
            mov     esp,    ebp
            pop     ebp

SECTION .bss            ; uninitialized data
    c:      resd    1
    fh:     resd    1

fileops.asm

;   Contains file operations: 
;       open_file
;       ... TODO: read/write/close

SECTION .data       ; initialized data
    fread:      db  "r", 0

    merr:       db  "[FILE] error [%d:%d] %s", 10, 0
    mopf:       db  "[FILE] open: %s", 10, 0

SECTION .text       ; code
    extern _fopen
    extern _printf

    global open_file

    open_file:
        ;   stash base stack pointer
        push    ebp
        mov     ebp,    esp

        mov     eax,        [ebp + 8]
        mov     [fnarg],    eax
        push    DWORD       [fnarg]
        push    DWORD       mopf
        call    _printf
        add     esp,    8

        ;   open file
        push    DWORD  fread
        push    DWORD  [fnarg]
        call    _fopen
        add     esp,    8

        push    DWORD   [eax]
        xor     eax,    eax

        .done:
        ;   restore base stack pointer
        mov     esp,    ebp
        pop     ebp

        ret

SECTION .bss        ; uninitialized data
    fnarg:      resb    128             ; reserve 128 bytes for file name
    fhndl:      resd    1

当前输出:

D:\asmplus>.\exes\parse .\tsources\s1.txt
[MAIN] call open_file: .\tsources\s1.txt
[FILE] open: .\tsources\s1.txt
[MAIN] ret: 2

这就是你的全部代码吗?如果你在它之后没有任何东西,它当然会崩溃,因为你没有通过 call _exit 或简单地 returning.

正确终止你的程序

另请注意,您通过 add esp, 8 清理了堆栈,因此您不再有可用的 space 试图将参数移入其中。您正在覆盖堆栈上的内容,例如 return 地址,如果您尝试从您的函数中 return ,这将给您带来问题。当您真的不再需要插槽时,您可以将 add 向下移动到 call _fopen 之后。

更正后的版本可能更像:

push        DWORD               fname
push        DWORD               mopf
call        _printf

mov         DWORD [esp],        fname
mov         DWORD [esp + 4],    fread
call        _fopen
add         esp,    8           ; clean up stack use
xor         eax, eax            ; 0 return value
ret

-或-

push        DWORD               fname
push        DWORD               mopf
call        _printf
add         esp,    8           ; clean up stack use

push        DWORD               fread
push        DWORD               fname
call        _fopen
add         esp,    8           ; clean up stack use
xor         eax, eax            ; 0 return value
ret