2009-06-21 135 views
64

我想在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

回答

29

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

104

這個例子顯示瞭如何直接轉到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 
4

除非你打電話一些功能,這是不是在所有瑣碎。 (而且,嚴肅地說,在調用printf和調用win32 api函數之間沒有真正的複雜性。)

即使DOS int 21h實際上只是一個函數調用,即使它是一個不同的API。

如果你想這樣做沒有你需要跟直接視頻硬件的幫助,可能寫「世界,你好」的字母的位圖轉換爲一個幀緩衝。即使這樣,顯卡也在將這些內存值轉換成VGA/DVI信號。

需要注意的是,真的,沒有這東西一路下跌到硬件在ASM比C.任何一個更有趣的「Hello World」程序歸結爲一個函數調用。 ASM的一個好處就是你可以使用任何你想要的ABI都相當簡單;你只需要知道ABI是什麼。

15

這些都是使用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 
4

如果你想使用NASM和Visual Studio的鏈接器(link.exe)與anderstornvig的Hello World例子,你將不得不手動鏈接包含printf()函數的C Runtime Libary。

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

希望這可以幫助別人。

12

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

7

爲了得到一個.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)。

2

最好的例子是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操作系統相連。 在啓動過程中,它將轉換爲可調用地址表,您可以在程序中使用該表。