I searched the internet rather, an example of a NASM x64 for windows, but I found just one, and, not work :(, just found for linux, code someone could show an example of how to create a Hello world NASM x64 windows
Asked
Active
Viewed 3,398 times
2
-
1It would be helpfull if you copied these "hello World" examples to the question, rather then just posting the links. I guess something like this can be usefull. – Devolus Dec 07 '13 at 19:29
-
1http://forum.nasm.us has some win64 examples that might be useful. – Frank Kotler Dec 07 '13 at 21:14
-
1What means "not work"? (Which error message / which behaviour / ...) – Martin Rosenau Dec 07 '13 at 21:40
2 Answers
1
A topic talking about that : https://openclassrooms.com/forum/sujet/nasm-win64-bug-hello-world. Someone brings up a solution in NASM [Win64].
main.asm
extern GetStdHandle
extern WriteFile
extern Sleep
extern ExitProcess
%define STD_OUTPUT_HANDLE (-11)
section .data
hello_str db "Hello World", 13, 10
hello_size equ ($ - hello_str)
output_handle dq 0
section .text
global main
main:
;Aligne la pile
and rsp, 0xFFFF_FFFF_FFFF_FFF0
mov rbp, rsp
;Récupère l'output standart
mov ecx, STD_OUTPUT_HANDLE
call GetStdHandle
mov [output_handle], rax
;Affiche le message
;Shadow Space
sub rsp, 48
mov rcx, [output_handle]
mov rdx, hello_str
mov r8d, hello_size
mov r9, 0
mov QWORD [rsp + 32], 0
call WriteFile
;Détruit l'espace de pile alloué pour les paramètres de la fonction
add rsp, 48
;Pause de 1000 millisecondes pour donner le temps de voir
;Shadow Space
sub rsp, 0x20
mov ecx, 1000
call Sleep
;Quitte
xor rcx, rcx
call ExitProcess
make.bat
@echo off
nasm.exe -fwin64 main.asm -o Obj/main.o
gpp.exe -s -m64 Obj/main.o -o hello.exe C:\Windows\System32\kernel32.dll
pause
"Note that I link with g++, but I think you can adapt it to your linker."

r0t0r
- 51
- 2
-
1`GetStdHandle` follows the same calling convention as other functions; you should reserve shadow space (and the space you're going to need later) *before* calling it. Or not at all, since your `main` doesn't return (instead calling an exit function), just let main's own shadow space and return address get overwritten like you already did for `GetStdHandle`. It certainly doesn't make sense to keep adjusting RSP during the function, like `add rsp, 48` / `sub rsp, 0x20`. – Peter Cordes Jun 16 '21 at 10:46
-
1Also, you should be using `default rel` so `mov rcx, [output_handle]` will use a RIP-relative addressing mode (more efficient than 32-bit absolute `[disp32]`). Or better, just use registers (or at least the stack; you even set up RBP as a frame pointer...), not static storage. e.g. `mov rcx, rax`, if file handles are really 64-bit in Windows. (Apparently all Windows Handles are 32-bit: [What is the range of a Windows HANDLE on a 64 bits application?](https://stackoverflow.com/q/18266626) so `mov ecx, eax` to zero-extend it into RCX) – Peter Cordes Jun 16 '21 at 10:51
-
1Having every Windows programs do its own sleep or wait-for-input is kind of an anti-pattern. Developers should set up an environment where they run a command in an existing terminal, or a new terminal that stays open until manually closed. Or use a .bat or something to run a program and then pause. – Peter Cordes Jun 16 '21 at 11:18
-
(I guess you just copied this code that someone else wrote, but now it's in your answer so it's your recommendation for a Hello World example.) – Peter Cordes Jun 16 '21 at 11:20
0
I just wrote a minimal windows 64 assembly code file. I compile it with nasm and I link it with ld.exe. I am not an expert. I am learning but I have noticed a lack of a simple code file. Source asm file is:
bits 64
default rel
MB_OK equ 0
NULL equ 0
extern MessageBoxA
extern ExitProcess
section .text
push rbp
mov rbp, rsp
mov rcx, MB_OK
lea rdx, mensaje2
lea r8, mensaje1
mov r9, NULL
sub rsp, 32
call MessageBoxA
xor rcx, rcx
sub rsp, 32
call ExitProcess
section .data
mensaje1: db "Hola colega", 0
mensaje2: db "Esto es una prueba", 0
I compile it with this makefile:
EXE=a.exe
ASMB=nasm.exe
LINK=ld.exe
ASMFLAGS=
LDFLAGS = -LC:\SinInstalacion\Desarrollo\mingw64\x86_64-w64-mingw32\lib -lkernel32 -luser32
OBJS=main.o
all: $(EXE)
$(EXE): $(OBJS)
$(LINK) -o $(EXE) $(OBJS) $(LDFLAGS)
%.o: %.asm
$(ASMB) -f win64 $< -o $@ $(ASMFLAGS)
clean:
del $(OBJS) $(EXE)
I wrote this post because I have not found an example in Google.
Forgive my mistakes.
Cheers.
I needed to add debug information to the exe file to be debugged with gdb. I changed makefile to:
EXE=a.exe
ASMB=nasm.exe
LINK=ld.exe
ASMFLAGS=-g -F dwarf
LDFLAGS =-g -LC:\SinInstalacion\Desarrollo\mingw64\x86_64-w64-mingw32\lib -lkernel32 -luser32
OBJS=main.o
all: $(EXE)
$(EXE): $(OBJS)
$(LINK) -o $(EXE) $(OBJS) $(LDFLAGS)
%.o: %.asm
$(ASMB) -f elf64 $< -o $@ $(ASMFLAGS)
clean:
del $(OBJS) $(EXE)
I hope it could be useful.

José Antonio López Cano
- 166
- 1
- 4
-
For debugging asm, I usually use `layout asm` or `layout reg` / `layout next`, so GDB is disassembling the machine code, not showing me the source file. Then it doesn't need debug info, just the symbols. (Also, DWARF debug info in a PE / COFF executable? I thought Windows would have its own debug-info format to go with its non-ELF object-file / executable format. But if GDB understands it, then cool.) – Peter Cordes Sep 01 '23 at 21:37
-
Standard NASM syntax for `lea rdx, mensaje2` is `lea rdx, [mensaje2]`. Without the square brackets, it's only supported because of NASM 2.15 or 2.16's MASM-compatibility changes that make LEA special for this. (https://nasm.us/doc/nasmdoc6.html#section-6.5) LEA needs a memory source operand, not an immediate, and a symbol name without square brackets is normally an immediate. ([Basic use of immediates vs. square brackets in YASM/NASM x86 assembly](https://stackoverflow.com/q/10362511)). But yes, with `default rel` (good), and recent NASM, you get `lea rdx, [rel mensaje2]` – Peter Cordes Sep 01 '23 at 21:42
-
You don't need (and shouldn't do) `sub rsp, 32` before *every* call. Do it once at the top of the function to reserve shadow space that will get reused for each callee. RSP needs to be 16-byte aligned before a `call` (so functions can assume RSP%16 == 8 on function entry), so whether you sub `16*n + 8` or `16*n` depends on whether you did an even or odd number of pushes on function entry. Other than alloca / VLAs, RSP shouldn't move except in the function prologue. – Peter Cordes Sep 01 '23 at 21:46