我可以看到您的代码有几个问题。首先,你有一个下划线 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 代码(但会链接到那个“启动代码”)。快乐你好世界!:)