为什么 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
环境,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