如何在Windows下编译hello world?

我想在Windows下编写一些基本的东西,我正在使用NASM,但是我什么都不能工作。

如何在没有Windows上的C函数的帮助下编写和编译hello world?

NASM的例子 。

; ---------------------------------------------------------------------------- ; helloworld.asm ; ; This is a Win32 console program that writes "Hello, World" on one line and ; then exits. It needs to be linked with a C library. ; ---------------------------------------------------------------------------- global _main extern _printf section .text _main: push message call _printf add esp, 4 ret message: db 'Hello, World', 10, 0 

然后运行

 nasm -fwin32 helloworld.asm gcc helloworld.obj a 

还有没有使用C库的Nasm的Hello World的无知新手指南 。 那么代码将如下所示。

 org 100h mov dx,msg mov ah,9 int 21h mov ah,4Ch int 21h msg db 'Hello, World!',0Dh,0Ah,'$' 

祝你好运。

此示例显示如何直接转到Windows API,而不是在C标准库中链接。

  global _main extern _GetStdHandle@4 extern _WriteFile@20 extern _ExitProcess@4 section .text _main: ; DWORD bytes; mov ebp, esp sub esp, 4 ; hStdOut = GetstdHandle( STD_OUTPUT_HANDLE) push -11 call _GetStdHandle@4 mov ebx, eax ; WriteFile( hstdOut, message, length(message), &bytes, 0); push 0 lea eax, [ebp-4] push eax push (message_end - message) push message push ebx call _WriteFile@20 ; ExitProcess(0) push 0 call _ExitProcess@4 ; never here hlt message: db 'Hello, World', 10 message_end: 

要编译,你需要NASM和LINK.EXE(从Visual Studio标准版)

    nasm -fwin32 hello.asm
    link / subsystem:console / nodefaultlib / entry:main hello.obj 

这些是使用Windows API调用的Win32和Win64示例。 他们是MASM而不是NASM,但是看看他们。 你可以在这篇文章中find更多的细节。

 ;---ASM Hello World Win32 MessageBox .386 .model flat, stdcall include kernel32.inc includelib kernel32.lib include user32.inc includelib user32.lib .data title db 'Win32', 0 msg db 'Hello World', 0 .code Main: push 0 ; uType = MB_OK push offset title ; LPCSTR lpCaption push offset msg ; LPCSTR lpText push 0 ; hWnd = HWND_DESKTOP call MessageBoxA push eax ; uExitCode = MessageBox(...) call ExitProcess End Main ;---ASM Hello World Win64 MessageBox extrn MessageBoxA: PROC extrn ExitProcess: PROC .data title db 'Win64', 0 msg db 'Hello World!', 0 .code main proc sub rsp, 28h mov rcx, 0 ; hWnd = HWND_DESKTOP lea rdx, msg ; LPCSTR lpText lea r8, title ; LPCSTR lpCaption mov r9d, 0 ; uType = MB_OK call MessageBoxA add rsp, 28h mov ecx, eax ; uExitCode = MessageBox(...) call ExitProcess main endp End 

要使用MASM汇编和链接这些,请将其用于32位可执行文件:

 ml.exe [filename] /link /subsystem:windows /defaultlib:kernel32.lib /defaultlib:user32.lib /entry:Main 

或者这对于64位可执行文件:

 ml64.exe [filename] /link /subsystem:windows /defaultlib:kernel32.lib /defaultlib:user32.lib /entry:main 

Flat Assembler不需要额外的连接器。 这使得汇编编程非常简单。 它也可用于Linux。

这是来自Fasm的hello.asm例子:

 include 'win32ax.inc' .code start: invoke MessageBox,HWND_DESKTOP,"Hi! I'm the example program!",invoke GetCommandLine,MB_OK invoke ExitProcess,0 .end start 

Fasm创build一个可执行文件:

 > fasm hello.asm
平面汇编程序版本1.70.03(1048575千字节内存)
 4遍,1536字节。

这是IDA的程序:

在这里输入图像描述

您可以看到三个调用: GetCommandLineMessageBoxExitProcess

为了得到带有NASM'compiler和Visual Studio的链接器的.exe,这段代码工作正常:

 global WinMain extern ExitProcess ; external functions in system libraries extern MessageBoxA section .data title: db 'Win64', 0 msg: db 'Hello world!', 0 section .text WinMain: sub rsp, 28h mov rcx, 0 ; hWnd = HWND_DESKTOP lea rdx,[msg] ; LPCSTR lpText lea r8,[title] ; LPCSTR lpCaption mov r9d, 0 ; uType = MB_OK call MessageBoxA add rsp, 28h mov ecx,eax call ExitProcess hlt ; never here 

如果这个代码保存在例如“test64.asm”,然后编译:

 nasm -f win64 test64.asm 

生成“test64.obj”然后从命令提示符链接:

 path_to_link\link.exe test64.obj /subsystem:windows /entry:WinMain /libpath:path_to_libs /nodefaultlib kernel32.lib user32.lib /largeaddressaware:no 

其中path_to_link可能是C:\ Program Files文件(x86)\ Microsoft Visual Studio 10.0 \ VC \ bin或您的计算机中的link.exe程序, path_to_libs可能是C:\ Program Files文件(x86)\ Windows工具包\ 8.1 \ Lib \ winv6.3 \ um \ x64或者你的库(在这个例子中,kernel32.lib和user32.lib都在同一个地方,否则为你需要的每个path使用一个选项)和/ largeaddressaware:no option is必须避免链接器抱怨地址长(在这种情况下为user32.lib)。 此外,如果在这里完成,如果从命令提示符调用Visual的链接器,则需要先设置环境(运行一次vcvarsall.bat和/或参见MS C ++ 2010和mspdb100.dll )。

除非你调用某个函数,否则这并不重要。 (而且,严肃地说,调用printf和调用win32 API函数之间的复杂性并没有真正的区别。)

即使DOS int 21h实际上只是一个函数调用,即使它是一个不同的API。

如果你想在没有帮助的情况下做,你需要直接与你的video硬件进行交stream,可能会把“Hello world”字母的位图写入帧缓冲区。 即使这样,显卡也在将这些内存值转换成VGA / DVI信号。

需要注意的是,实际上,这些东西一直到硬件,在ASM中比在C中更有趣。一个“hello world”程序归结为一个函数调用。 ASM的一个好处是你可以使用任何你想要的ABI; 你只需要知道ABI是什么。

如果要使用NASM和Visual Studio的链接器(link.exe)和anderstornvig的Hello World示例,则必须手动链接到包含printf()函数的C运行时库。

 nasm -fwin32 helloworld.asm link.exe helloworld.obj libcmt.lib 

希望这有助于某人。

最好的例子是fasm,因为fasm没有使用链接器,它通过另一个不透明的复杂层隐藏了Windows编程的复杂性。 如果你满足于一个写入gui窗口的程序,那么在fasm的示例目录中就有一个例子。

如果你想要一个控制台程序,允许标准input和标准输出,这也是可能的。 有一个(helas高度非平凡的)示例程序可用,不使用gui,并且严格地与控制台一起工作,这就是fm本身。 这可以被细化到要点。 (我已经写了第四个编译器,这是另一个非gui的例子,但它也是非平凡的)。

这样的程序具有以下命令来生成正确的可执行头,通常由链接器完成。

 FORMAT PE CONSOLE 

名为“.idata”的部分包含一个表,可以帮助启动窗口在启动时将函数的名称与运行时地址相结合。 它还包含对Windows操作系统KERNEL.DLL的引用。

  section '.idata' import data readable writeable ... 

您的程序在“.text”部分。 如果您声明该部分是可读的可写和可执行文件,那么这是您需要的唯一部分。

  section '.text' code executable readable writable 

您可以调用您在.idata部分声明的所有设施。 对于控制台程序,您需要_GetStdHandle来查找他的标准input和标准输出的文件描述符(使用符号名称,如在include文件win32a.inc中find的STD_INPUT_HANDLE)。 一旦你有文件描述符,你可以做WriteFile和ReadFile。 所有的函数都在kernel32文档中描述。 您可能已经意识到了这一点,或者您不会尝试汇编编程。

总而言之:有一个与asci名称耦合到Windows操作系统的表。 在启动期间,这将转换为您在程序中使用的可调用地址表。