2

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

x64 assembly code for NASM linux

x64 Assembly code for NASM windows

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Alexandre
  • 1,985
  • 5
  • 30
  • 55

2 Answers2

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
  • 1
    Also, 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
  • 1
    Having 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.

  • 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