我想在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'
我想念什么?如何解决此错误?
答案 0 :(得分:5)
该Hello World程序正在尝试手动创建PE导入表。为了使它起作用,您需要仔细地指示链接器(PE部分未绑定到PE目录,idata
仅是名称)。
在该来源中进行了进一步的假设(例如,图像的基址和对CRT的需求)。
老实说,这只是胡说。正确使用链接器,例如Jester shown。
老实说,整个Wikipedia部分充其量只是提供信息。
长话短说:永远不要将Wikipedia用作编程教程。
主要可以通过两种方式创建32位Windows控制台程序:
使用C运行时(CRT)
这使您可以使用通用的C函数(在所有printf
之上)。
有两种使用CRT的方法:
main
/ WinMain
/ DllMain
和unicode变体)由CRT调用,该CRT首先由正确设置的PE入口点运行。_mainCRTStartup
之类的东西来初始化CRT,而CRT则调用您的主要功能。 msvcrt.dll
,对于Visual Studio安装随附的版本,CRT主dll为msvcrtXX0.dll
(其中XX
取决于VS版本)。 仅使用Windows API
Windows API是OS公开的功能,这些正是CRT实现最终要调用的功能。
您可以使用Windows API和CRT(常见的情况是图形应用程序具有静态链接的CRT,并使用WinMain
作为入口点-Windows API与C实用程序功能混合在一起)或单独使用Windows API。
单独使用它们时,您会获得更小,更快和更容易执行的文件。
要使用1.1,您需要CRT目标文件,并且这些文件通常与编译器一起提供(它们曾经与Windows SDK一起提供,但是现在VS是免费的,因此Microsoft将它们移至VS软件包中-公平,但是VS是数量级的比SDK重)。
1.2和2不需要这些目标文件。
但是请注意,编译器/汇编器/链接器的兼容性可能会令人讨厌,尤其是用于链接外部API的.lib
机制(基本上是libs文件是使链接器找到运行时将由加载器解析的功能的一种方法。 -即在外部DLL中定义的那些)。
首先,写您好,世界!使用方法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位示例涉及更多的内容,但仍然很有用。
这是Wikipedia文章试图使用的内容。
在分析该特定代码之前,让我展示一下如何编写它:
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
Wikipedia的代码正在创建一个.idata
部分,用于存储PE导入地址表。
这是一个愚蠢的举动,链接器用于基于目标文件的动态依赖关系来生成该表。
要建立该程序链接,我们需要:
0x400000
。可以使用任何链接器来完成此操作(对于golink,请使用/base 0x400000
)。 .text
部分的起点。我不知道link.exe
是否可以将.text
作为有效的符号名称,或者是否允许指定相对于.text
的入口点,但这似乎不太可能。 Golink不允许这样做。简而言之,可能缺少标签。 .idata
部分。我不知道任何允许这样做的链接器(尽管它可能存在)。 简而言之,算了吧。
这就是link Jester pointed out所使用的。
汇编代码与1.2相同,但是您使用MinGW进行链接。