Article by Ayman Alheraki on January 11 2026 10:37 AM
This example shows how to create a simple Windows application in pure x86 Intel syntax assembly, which:
Creates a window
Allocates a framebuffer in memory
Draws a red square pixel-by-pixel into the buffer
Displays it on the window using StretchDIBits (Windows GDI)
Use MinGW or TDM-GCC on Windows with as (GAS) and gcc tools.
Assemble with Intel syntax: add .intel_syntax noprefix directive.
Build commands:
as --32 --gstabs --intel gfx.asm -o gfx.ogcc -m32 gfx.o -o gfx.exe -lgdi32./gfx.exeasmCopyEdit.intel_syntax noprefix.section .data className: .asciz "MyWindow" windowTitle: .asciz "GAS CPU Graphics" msg: .int 0 hInstance: .int 0 width: .int 640 height: .int 480 bufferSize: .int 640*480*4
bmiHeader: .int 40 # biSize .int 640 # biWidth .int -480 # biHeight (negative = top-down) .short 1 # biPlanes .short 32 # biBitCount .int 0 # biCompression (BI_RGB) .int 640*480*4 # biSizeImage .int 0 # biXPelsPerMeter .int 0 # biYPelsPerMeter .int 0 # biClrUsed .int 0 # biClrImportant
.section .bss hWnd: .skip 4 msgStruct: .skip 48 buffer: .skip 640*480*4
.section .text.global WinMainCRTStartup
WinMainCRTStartup: call GetModuleHandleA mov [hInstance], eax
# Register window class sub esp, 64 mov dword ptr [esp], 0x30 # cbSize lea eax, [WndProc] mov dword ptr [esp+4], eax # lpfnWndProc mov eax, [hInstance] mov dword ptr [esp+8], eax # hInstance mov dword ptr [esp+56], offset className # lpszClassName call RegisterClassExA add esp, 64
# Create window push 0 push 0 push [height] push [width] push 0xCF0000 # WS_OVERLAPPEDWINDOW push 0 push 0 push 0 push offset windowTitle push offset className call CreateWindowExA mov [hWnd], eax push eax call ShowWindow
mainloop: push offset msgStruct call GetMessageA test eax, eax jz exit_loop push offset msgStruct call TranslateMessage push offset msgStruct call DispatchMessageA jmp mainloop
exit_loop: call ExitProcess
#---------------------------# Window Procedure#---------------------------WndProc: push ebp mov ebp, esp mov eax, [ebp + 12] # uMsg cmp eax, 0xF # WM_PAINT jne defproc
# BeginPaint sub esp, 64 lea eax, [esp] push eax mov eax, [hWnd] push eax call BeginPaint mov esi, eax # HDC
# Draw red square into buffer mov ecx, 200 # y loop starty_loop: mov edx, 200 # x loop startx_loop: mov eax, ecx imul eax, 640 # y * width add eax, edx # + x shl eax, 2 # * 4 bytes per pixel lea edi, [buffer + eax] mov dword ptr [edi], 0x000000FF # Red pixel (ARGB) inc edx cmp edx, 280 jl x_loop inc ecx cmp ecx, 280 jl y_loop
# Prepare BITMAPINFO pointer lea eax, [bmiHeader]
# Call StretchDIBits( # HDC, xDest=0, yDest=0, DestWidth=640, DestHeight=480, # xSrc=0, ySrc=0, SrcWidth=640, SrcHeight=480, # buffer, &bmiHeader, DIB_RGB_COLORS=0, SRCCOPY=0x00CC0020 push 0x00CC0020 # SRCCOPY push 0 # DIB_RGB_COLORS push eax # BITMAPINFO* push offset buffer # Bits push 480 # SrcHeight push 640 # SrcWidth push 0 # SrcY push 0 # SrcX push 480 # DestHeight push 640 # DestWidth push 0 # DestY push 0 # DestX push esi # HDC call StretchDIBits
push esi call EndPaint add esp, 64 mov eax, 0 pop ebp ret
defproc: cmp eax, 2 # WM_DESTROY jne defproc2 call PostQuitMessage mov eax, 0 pop ebp ret
defproc2: push dword ptr [ebp+16] # lParam push dword ptr [ebp+12] # wParam push dword ptr [ebp+8] # uMsg push dword ptr [ebp+4] # hwnd call DefWindowProcA pop ebp ret.intel_syntax noprefix tells GAS to use Intel syntax (no % prefixes, normal Intel opcodes).
The code manually does pixel addressing and calls Windows API directly.
buffer is a linear 32-bit ARGB framebuffer.
Uses StretchDIBits to blit the buffer on the window.
The red square is 80x80 pixels drawn at (200,200).
Save as gfx.asm
Open MinGW terminal or cmd with MinGW tools in PATH
Run:
as --32 --intel gfx.asm -o gfx.ogcc -m32 gfx.o -o gfx.exe -lgdi32Run gfx.exe
This example proves that pure assembly with CPU-only drawing is feasible on Windows by:
Allocating a framebuffer in memory
Implementing pixel-level drawing logic
Using Windows GDI calls from assembly
Building with GAS in Intel syntax
You can extend this by adding lines, circles, text rendering, or even animations, all coded in assembly.