在 FASM 中调用 _getch 之前无法弄清楚我必须将什么推入堆栈

Can't figure out what I must I push to the stack before calling `_getch` in FASM

我正在使用 SASM IDE by Dmitry Manushin 在 FASM 中编写程序。我的代码如下:

format ELF

section '.data' writeable
    msg db 'Hello, world of Flat ASM!',  0Dh, 0Ah, 00h ; terminate with null string
    buffer rb 20
    inp_buf_size rw 1
    pkey db 'Press any key to exit ...', 0h
    formatStr db "%s", 0

section '.text' executable
public _main
extrn _printf
extrn _getch
extrn _getche
_main:
    mov ebp, esp; for correct debugging
    push msg ; push message onto the stack
    push formatStr ; push formatter onto the stack
    call _printf ; call the printf method to print the message
    add esp, 8 ; clean up
    xor eax, eax
    ; press any key to exit
    mov ebp, esp; for correct debugging
    push pkey ; push message onto the stack
    push formatStr ; push formatter onto the stack
    call _printf ; call the printf method to print the message
    add esp, 8
    xor eax, eax

    ; get input here, using getch or getche (how? What must be pushed)
    ; mov ebp, esp; for correct debugging
    ; push buffer
    ; call _getch
    ; add esp, 8
    ; xor eax, eax

    ret

按预期打印 "Hello, world ..." 和 "Press any key ..." 代码。我坚持的是如何让程序使用 _getch 等待 for/read 单个字符进入缓冲区。 (如果有的话,我应该在调用 _getch 之前将什么压入堆栈?)我尝试将值移入 ah 并使用中断,但这会导致程序崩溃。

这里发生了一些事情 format ELF 告诉 FASM 创建一个 Linux 目标文件。这感觉有点奇怪,因为你是 运行 Windows。但让它起作用的是 SASM 使用 Linux gcc 工具链的 MinGW 版本来创建可执行文件。这意味着您可以编写一些 Linux 程序集,但并非所有内容都可以是 Linux 语法。

另一个问题是 getch 不是 POSIX,所以可能会导致问题,请改用 getchar

最后,windows 不会通过在 eax 中使用 return 值来退出程序。

xor eax, eax
ret
因此,

部分将在 Windows 中挂起。一个安全的方法是 call _ExitProcess 在堆栈上传递 0。

似乎 SASM 期望任何输入都预先输入到输入框中,因此不会等待 _getchar。我保留它是为了展示如果 SASM 不这样做它会如何工作。 运行 使用 FASM 直接组装的类似代码按预期工作。

把所有这些放在一起我们得到这个:

format ELF

section '.data' writeable
    msg db 'Hello, world of Flat ASM!',  0Dh, 0Ah, 00h
    pkey db 'Press any key to exit ...', 0h
    formatStr db "%s", 0

public _main
extrn _printf
extrn _getchar
extrn _ExitProcess

section '.text' executable

_main:
    push msg 
    push formatStr
    call _printf

    push pkey
    push formatStr
    call _printf

    call _getchar
    push 0
    call _ExitProcess

为了简单起见,我删除了堆栈代码,因为这只是一个 hello world。

当我发现你的问题时,我实际上是在试图弄清楚如何让 SASM 在 Windows 上运行,在我写下我的其他答案后,我偶然发现了一种能够使用原生 Windows FASM 语法。在构建选项中,选中 "Disable linking" 框并将 $PROGRAM.OBJ$ "Assembly options" 参数更改为 $PROGRAM$。这将导致它使用 Windows FASM.exe 到 assemble 你的 exe 并跳过 Linux 样式对象创建和 gcc 链接。

一个很大的负面影响是调试器不再工作,这对我来说是一个交易杀手。

为了展示 Windows FASM 代码的样子,这是我的 hello world:

format PE console
entry _main
include '%fasm_inc%/win32a.inc'

section '.data' data readable

hello db 'Hello world!', 0

section '.text' code readable executable

_main:
    invoke _printf, hello
    invoke _getchar
    push eax
    invoke _putchar
    invoke _ExitProcess, 0

section '.idata' import data readable

library kernel32, 'kernel32.dll',\
    msvcrt, 'msvcrt.dll'

import kernel32,\
        _ExitProcess, 'ExitProcess'
import msvcrt,\
        _printf, 'printf',\
        _getchar, 'getchar',\
        _putchar, 'putchar'

我添加了 _putchar 以表明 _getchar 正在使用输入框中的文本并且 SASM 不等待用户输入。