如前所述,您的程序显然缺少系统调用。
在 Windows 下(就您为 Windows 生成 .EXE 文件而言)没有直接的系统调用。相反,您必须调用 Windows 附带的 DLL 中的函数。
例子:
mov ecx,len
push ecx
mov ecx,msg
push ecx
mov ecx,1
push ecx
call _write
add esp,12
在 32 位窗口(或在 64 位窗口中运行的 32 位程序)中,基本上有两种类型的函数:stdcall (= WINAPI, CALLBACK, PASCAL) 和 cdecl。
对于这两种类型的函数,参数都必须在堆栈中(第一个参数必须在 ESP+0,第二个参数必须在 ESP+4,依此类推)所以你“推送”参数,而最后一个参数首先被推送(在示例“1”是第一个,“len”是最后一个)。函数的结果(如果有)在 EAX 寄存器中返回(只要它不是浮点值)。
然后调用在 DLL 中定义的函数。最后,该函数将执行系统调用,但是此系统调用可能是特定于版本的!你不必关心这个。
在“stdcall”函数的情况下,该函数将从堆栈中删除参数。(对于具有可变数量参数的函数 - 如 wsprintf - 仅删除强制参数。)在汇编程序中,此类函数被命名为:
_Name@nnn
而“Name”是 C 语言中已知的函数的名称,而 nnn 是将从堆栈中删除的字节数。大多数低级 Windows 函数都是 stdcall 函数。请注意,使用字符串的函数通常以“A”结尾表示 ASCII,或以“W”结尾表示 UNICODE 字符串。您通常使用“A”变体。示例:调用函数“MessageBox”:
(push 4 arguments)
call _MessageBoxA@16
大多数 C 标准库函数都是“cdecl”——参见上面的“write”示例。Cdecl 函数不会调整堆栈指针,因此您必须在“call”指令之后添加“add esp,nnn”。该名称只需在下划线后添加 C 函数名称即可(例如“write()”->“call _write”)。