如何在Windows下编译hello world?

问题描述:

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

如何编写和编译的Hello World无C函数在Windows的帮助?

+0

还可以查看Steve Gibson的[Small Is Beautiful](http://www.grc.com/smgassembly.htm)Windows程序集入门工具包。 – Jeremy 2010-04-16 14:51:39

+0

不使用c库是一个有点奇怪的约束。必须在MS-Windows操作系统中调用一些库。可能是kernel32.dll。微软是用c还是Pascal写的,似乎没有关系。这是否意味着只能调用OS提供的函数,而在Unix类型的系统中又称为系统调用? – 2017-02-16 11:16:43

+0

对于C库,我假设他或她的意思是不使用像GCC或MSVC那样的C运行库。当然,他或她将不得不使用一些标准的Windows DLL,比如kernel32.dll。 – 2017-05-13 19:23:55

NASM examples

; ---------------------------------------------------------------------------- 
; 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 

还有The Clueless Newbies Guide to Hello World in Nasm没有使用C++类库。然后代码将如下所示。

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

祝你好运。

+13

这个问题明确提到“不使用C库” – 2009-06-21 10:24:40

+0

没有可靠的方法来做到这一点,而没有在某个时候调用C函数。除非通过“C函数”来表示“标准C函数”。 – 2009-06-21 12:36:40

这个例子显示了如何直接转到Windows API和C标准库中没有链接。

global _main 
    extern [email protected] 
    extern [email protected] 
    extern [email protected] 

    section .text 
_main: 
    ; DWORD bytes;  
    mov  ebp, esp 
    sub  esp, 4 

    ; hStdOut = GetstdHandle(STD_OUTPUT_HANDLE) 
    push -11 
    call [email protected] 
    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 [email protected] 

    ; ExitProcess(0) 
    push 0 
    call [email protected] 

    ; 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 

除非你打电话一些功能,这是不是在所有琐碎。 (而且,严肃地说,在调用printf和调用win32 api函数之间没有真正的复杂性。)

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

如果你想这样做没有你需要跟直接视频硬件的帮助,可能写“世界,你好”的字母的位图转换为一个帧缓冲。即使这样,显卡也在将这些内存值转换成VGA/DVI信号。

需要注意的是,真的,没有这东西一路下跌到硬件在ASM比C.任何一个更有趣的“Hello World”程序归结为一个函数调用。 ASM的一个好处就是你可以使用任何你想要的ABI都相当简单;你只需要知道ABI是什么。

这些都是使用Windows API调用Win32和Win64的例子。他们是为了MASM而不是NASM,但是看看他们。您可以在this文章中找到更多详细信息。

;---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 

如果你想使用NASM和Visual Studio的链接器(link.exe)与anderstornvig的Hello World例子,你将不得不手动链接包含printf()函数的C Runtime Libary。

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

希望这可以帮助别人。

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创建一个可执行文件:

 
>fasm hello.asm 
flat assembler version 1.70.03 (1048575 kilobytes memory) 
4 passes, 1536 bytes. 

这是IDA程序:

enter image description here

你可以看到三个cal ls:​​,MessageBoxExitProcess

为了得到一个.exe与NASM'compiler和Visual Studio的链接此代码工作正常:

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 Kits \ 8.1 \ Lib \ winv6。 3 \ um \ x64或任何地方你的库(在这种情况下,kernel32.lib和user32.lib都在同一个地方,否则为你需要的每个路径使用一个选项)和/largeaddressaware:没有选项是必要的以避免链接器抱怨地址长(在这种情况下为user32.lib)。 另外,因为它是在这里完成的,所以如果从命令提示符调用Visual的链接器,则有必要先设置环境(运行一次vcvarsall.bat和/或参见MS C++ 2010 and mspdb100.dll)。

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

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

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

FORMAT PE CONSOLE 

称为“的.idata” A部分包含一个表,启动时的运行时间地址的功能,这几个名字中会有帮助的窗口。它还包含对Windows操作系统KERNEL.DLL的引用。

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

您的程序在'.text'部分。如果您声明该部分可读写和可执行文件,则它是您需要的唯一部分。

section '.text' code executable readable writable 

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

总结:有一张带有asci名字的表格,与windows操作系统相连。 在启动过程中,它将转换为可调用地址表,您可以在程序中使用该表。