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



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

我有以下非常简单的程序集源:

SECTION .data       ; initialized data
    fname:      db  "c:asmplustsourcess1.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

我得到以下输出:

[文件] 打开: 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
[主] 调用open_file: .\t源\s1.txt
[文件] 打开: 。\t源\s1.txt
[主要] 回复: 2

这就是你所有的代码吗?如果你之后没有任何内容,它当然会崩溃,因为你没有通过执行call _exit或简单地返回来正确终止你的程序。

另请注意,您按add esp, 8清理堆栈,因此您不再有尝试将参数移动到的可用空间。您正在覆盖堆栈上的内容,例如返回地址,例如,如果您尝试从函数返回,这将给您带来问题。当您真的不再需要插槽时,您可以将该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

相关内容

最新更新