我可以看到您的代码有几个问题。首先,你有一个下划线 onglobal _main
但不是 on main:
。这些应该匹配。您可以在整个过程中使用下划线,或者 - 我会做的 - 根本不......对于 Windows,组装为nasm -f win32 --prefix _ test.asm
. 这将使其“可移植”,因为对于 Linux,它可以在--prefix _
没有下划线的情况下进行组装。Linux 不使用下划线global
或extern
符号。如果您有机会使用 OpenWatcom C,您可以使用--postfix _
. 是的,OpenWatcom 使用尾随下划线。是的,我知道他们告诉我们 C 是标准化的。但是一旦你深入了解,这并不是真的。
另一个大问题是,在调用之后_printf
,您需要add esp, 4
(或pop
一个虚拟寄存器)来“清理堆栈”。如果您使用的是 Windows API,它们使用“被调用者清理”的 STDCALL 调用约定,因此您不想这样做。混合 C 调用(CDECL 调用约定)和 Windows API 可能会令人困惑,但应该可以。
我认为 Carl 使用 gcc 链接它的想法是正确的。没有什么可以“编译”的,但 gcc 知道 ld 的正确命令行。gcc -o test.exe test.obj
可能就足够了(-m32
如果最新的 MinGW 期望使用 64 位代码,可能会添加)。这将链接到一些调用_main
. 这将略微增加可执行文件的大小,并且您“可能”没有它也可以相处,但这样做更容易。
在 Linux 中,我们可以直接使用 ld (命令行很可怕),但 ld 正在寻找_start
,而不是main
,作为入口点。我们可以告诉 ld -e main
,但是这个入口点没有被调用(!)并且没有可能的方法ret
!Windows 中的情况可能有所不同。您至少-lc
需要告诉 ld 我们想要那些 C 库。最容易“让 gcc 去做”——它不会触及你的 .asm 代码(但会链接到那个“启动代码”)。快乐你好世界!:)