MASM64 init

Learn Windows x86-64 assembly from one small program you can build, run, single-step, and take apart. Each lesson introduces one machine-level idea, explains the rule, and then shows only the source needed to make it concrete.

This guide uses Microsoft Macro Assembler, the Windows x64 ABI, and the MASM64 SDK. It assumes you can read simple code, but it does not assume previous assembly experience.
RegistersSmall, named pieces of working storage inside the CPU.
MemoryBytes reached through an address and interpreted with an explicit size.
FlagsOne-bit results that connect arithmetic to branches and loops.
The stackCall space, saved state, local storage, and the boundary between procedures.

Read an instruction left to right

MASM uses destination, source order. In mov rdx, rcx, the value in rcx is copied into rdx. Registers are not variables with fixed types: the instruction and operand spelling decide the width. A mov eax, 1 writes 32 bits; mov rax, 1 writes 64.

Comments begin with ;. Labels end with : and name places a jump can reach. Brackets such as [rsi + rcx * 8] mean “the memory at this calculated address.” Those few rules are enough to start reading real code.

From entry point to operating system

The program begins with a normal procedure frame. It reserves the call space required by Windows, obtains the console output handle, places four arguments in registers and one on the stack, then calls WriteFile.

The entry point reserves stack space, prepares Win32 arguments, and makes the call. source/main.asm
main proc frame
    sub rsp, 40
    .allocstack 40
    .endprolog
    ; --- print hello ---
    ; print something to the console using writefile then write to std out.
    ; this procedure also shows the win64 calling convention.
    ; -----------------------------------------------------------------------------
    mov rcx, std_output_handle    ; output handle arg
    call GetStdHandle    ; get handle from os

    ; --- print hello ---
    ; note: how to calculate param stack location:
    ; nth parm - 1 = (5 - 1) * 8 = 32 bytes
    ; -----------------------------------------------------------------------------
    mov rcx, rax    ; [0] hFile
    lea rdx, outputmessage    ; [1] lpBuffer
    mov r8, outputmessagelength    ; [2] nNumberOfBytesToWrite
    xor r9, r9    ; [3] lpNumberOfBytesWritten
    mov [rsp + 32], r9    ; [4] lpOverlapped
    call WriteFile    ; print

Build and run

  1. Open the x64 Native Tools Command Prompt for Visual Studio 2022.
  2. Run scripts/build.bat from the repository root.
  3. Run build/main.exe, or open it under Visual Studio with devenv build/main.exe.

Follow the learning path

Read the chapters in order the first time. Each one explains a small idea, shows a focused excerpt from the actual repository, and ends with rules worth remembering. The complete modules remain linked when you want to inspect them in context.

Every example comes from IbrahimHindawi/masm64-init. The website is generated from the same formatted source that builds the executable.