gpt4 book ai didi

windows - 在 Windows (MinGW) 上编译 Nasm 程序时未定义对 `WinMain' 的引用

转载 作者:可可西里 更新时间:2023-11-01 13:25:59 24 4
gpt4 key购买 nike

我想在 Windows 上编译 Hello World NASM example

我已将上面的代码粘贴到 main.asm 文件中,并使用以下命令将其编译为 obj 文件:

nasm -fwin32 .\main.asm -o main.obj

之后,我想将此 obj 文件编译为 exe,如下所示:
g++ .\main.obj -o main.exe -m32

但我收到此错误:
C:/Program Files (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/bin/../lib/gcc/i686-w64-mingw32/8.1.0/../../../../i686-w64-mingw32/lib/../lib/libmingw32.a(lib32_libmingw32_a-crt0_c.o):crt0_c.c:(.text.startup+0x39): undefined reference to `WinMain@16'

我想念什么?怎么可能修复这个错误?

最佳答案

该 Hello World 程序正在尝试手动创建 PE 导入表。为了使其工作,您需要小心地指示链接器(PE 部分与 PE 目录无关,idata 只是一个名称)。
在该源中进行了进一步的假设(例如图像的基地址和对 CRT 的需求)。
老实说,这只是废话。正确使用链接器,如 Jester shown .
老实说,整个维基百科部分充其量只是提供信息。
长话短说:永远不要将维基百科用作编程教程。
编辑 :维基百科页面上的 x86-64 Linux 示例已由 Peter Cordes 更新;其他人可能仍然具有误导性。
一些简短的理论
您可以主要通过两种方式创建 32 位 Windows 控制台程序:

  • 使用 C 运行时 (CRT)
    这让您可以使用常见的 C 函数(最重要的是 printf )。
    有两种使用 CRT 的方法:
  • 静态
    CRT 源代码编译产生的目标文件与源代码编译/汇编产生的目标文件相链接。
    CRT 代码完全嵌入在您的应用程序中。
    在这种情况下,您的主函数(main/WinMain/DllMain 和 unicode 变体)被首先由正确设置的 PE 入口点运行的 CRT 调用。
    为了使用此方法,您需要 CRT 对象文件,这些可以通过 Visual Studio 或 MinGW 找到(举两个例子)。
    执行顺序是: Windows 加载程序调用您的 PE 入口点,它被设置为类似 _mainCRTStartup 的内容。初始化 CRT 并且 CRT 调用您的主函数。
  • 动态
    CRT 主 dll 是 msvcrt.dll对于 Windows 安装附带的版本或 msvcrtXX0.dll对于 Visual Studio 安装附带的版本(其中 XX 取决于 VS 版本)。
    CRT dll 在 DLL 入口点中具有初始化和拆卸代码,因此只需将其放入 PE 导入表中,CRT 就会自动进行管理。
    执行顺序是:Windows 加载程序加载您的 PE 依赖项,包括 CRT DLL(按照上述方式初始化),然后调用您的 PE 入口点。

  • 仅使用 Windows API
    Windows API 是操作系统公开的函数,这些是 CRT 实现最终调用的函数。
    您可以使用 Windows API 和 CRT(常见情况是图形应用程序将 CRT 静态链接并使用 WinMain 作为入口点 - Windows API 与 C 实用程序函数混合在一起)或 Windows API独自的。
    单独使用它们时,您会得到一个更小、更快且易于执行的程序。

  • 要使用 1.1,您需要 CRT 目标文件,这些通常与编译器一起提供(它们曾经与 Windows SDK 一起提供,但现在 VS 是免费的,Microsoft 将它们移到 VS 包中 - 公平,但 VS 比SDK)。
    1.2 和 2 不需要这些目标文件。
    但是请注意,编译器/汇编器/链接器的兼容性可能是一个令人讨厌的野兽,尤其是 .lib用于链接外部 API 的机制(基本上,libs 文件是一种让链接器找到将在运行时由加载器解析的函数的方法——即那些在外部 DLL 中定义的函数)。
    你好,世界!
    方法二
    首先,编写Hello,World!使用方法2.,见 this other answer of mine .
    它是在 Windows SDK 中提供链接器时编写的,今天我使用 GoLink .
    它是一个极简的、非常易于使用的链接器。
    它的一个关键点是它不需要 .lib 文件,相反,您可以将外部函数所在的 DLL 的路径传递给它。
    NASM命令是一样的,链接使用:
     golink /console /entry main c:\windows\system32\kernel32.dll hello.obj -fo hello.exe
    未经测试 - 可选择添加 /largeaddressaware如果你的代码可以处理
    该示例适用于 64 位编程,它比 32 位编程更复杂,但无论如何可能有用。
    方法 1.2
    这就是维基百科文章试图使用的内容。
    在分析该特定代码之前,让我展示一下我将如何编写它:
    BITS 32

    GLOBAL _main

    EXTERN printf
    EXTERN exit

    SECTION .text

    _main:
    push strHelloWorld
    call printf
    add esp, 04h

    push 0
    call exit


    SECTION .data

    strHelloWorld db "Hello, world!", 13, 10, 0
    与 Wiki 的相比,这非常简单。
    要制作可执行文件:
    nasm -fwin32 helloworld.asm -o helloworld.obj
    golink /console /entry _main c:\windows\system32\msvcrt.dll helloworld.obj -fo helloworld.exe
    维基百科的代码正在创建一个 .idata存储 PE 导入地址表的部分。
    这是一个愚蠢的举动,链接器用于根据目标文件的动态依赖关系生成该表。
    要制作该程序链接,我们需要:
  • 告诉链接器基地址是 0x400000 .这可以通过任何链接器完成(golink 使用 /base 0x400000)。
  • 告诉链接器入口点是 .text节开始。不知道是不是link.exe可以带.text作为有效的符号名称,或者如果允许指定相对于 .text 的入口点但这似乎不太可能。 Golink 不允许这样做。简而言之,可能缺少标签。
  • 告诉链接器使导入目录指向 .idata部分。我不知道任何允许这样做的链接器(尽管它可能存在)。

  • 简而言之,忘记它。
    方法 1.1
    这是什么 link Jester pointed out正在使用。
    汇编代码与 1.2 相同,但您使用 MinGW 进行链接。

    关于windows - 在 Windows (MinGW) 上编译 Nasm 程序时未定义对 `WinMain' 的引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52966390/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com