Masm32: What you absolutely need to get started

Installation of the libraries

Step 1: Download the Masm32 SDK from (or the Windows 10 version) (you must ignore any Windows warnings)

Step 2: Open, and run install.exe - two minutes later, you will see a window Installation success

Step 3: You may or may not click "Yes" when the QEICON.VBS window pops up - decide yourself

Step 4: Close the small Installation is complete window (you may read the Intro.txt)

Step 5: You should install the MasmBasic package (all remarks in green below refer to this package, which is fully compatible with all Masm32 macros and libraries)

Step 6: As soon as you read in the upper right corner “... the usual disclaimers apply”, hit the F6 key

Step 7: If you see a "Missing tool" box, click OK to install UAsm; a few seconds later, see your first assembly program in action!
(If you don’t want to use RichMasm for some reason, at least get UAsm. Many of the new SSE+ instructions don’t work with the old MASM version 6.14 that comes with the Masm32 SDK. Newer versions of MASM exist, but some of them are pretty buggy, and compared to UAsm they are awfully slow.)

Optional but highly recommended for serious work:

- After installing MasmBasic, google for Win32.hlp; it might be available at this Modula-2 page as Win32 API Help file (check also the Petzold stuff). Extract Win32.hlp to \masm32\RichMasm\help\WIN32.HLP (this makes sure that context-sensitive F1 works in RichMasm)

- Get a debugger: Download OllyDbg and extract all files to \masm32\OllyDbg\*.*. If you use MasmBasic's RichMasm editor, insert int 3 somewhere in your code, hit F6 and see the debugger in action; Olly is very simple, you will need only the F7 ... F9 keys

- In case you do not have MS Office, install the free Microsoft Word Viewer: It will speed up RichMasm by more than a factor 20.

Hello World in Masm32 (in case you are impatient)

This is a very simple skeleton for testing your installation. Assemble, link & run it (in RichMasm: by pressing F6), or insert your first mov eax, 123 somewhere between start: and exit


include \masm32\include\

.data         ; initialised variables

MyAppName db "Masm32:", 0

MyReal8 REAL8 123.456

.data?       ; non-initialised (i.e. zeroed) variables

MyDword dd ?



  invoke MessageBox, 0, chr$("A box, wow!"), addr MyAppName, MB_OK

  mov eax, 123                                       ; just an example – launch OllyDbg to see it in action


end start


Help and tutorials, recommended reading


high level language in Masm: .if / .elseif / .endif, .Repeat ... .Until etc, a must read


how do instructions like mov, inc, add, sub etc work?


if you saved it there, select e.g. "CreateWindowEx" in RichMasm and hit F1


open it from the RichMasm File menu, "Guide to MasmBasic" 


if you find the time, study them all...


the Masm32 library functions


Masm32 macros


read it to understand why include \masm32\include\ is enough


sample code for all occasions

MasmBasic Quick Reference

use BASIC syntax (Open “I”, Print, Dim, Instr_, Dll, Declare, ...) in assembly

The Iczelion Tutorials

essential guide to programming Windows

University of Virginia x86 Assembly Guide

registers, memory and addressing, instructions, calling conventions

Randall Hyde’s Art of Assembly

one of the few good books on assembly programming

Masm Programmer’s Guide (search the web...)

essential guide for programming in Masm

Microsoft Macro Assembler Reference

online documentation at MSDN

Tips, Tricks and Traps

The following is addressed to those who have experience in a high level language such as BASIC or C.

You are bound to stumble over some assembler oddities - read this section carefully.

- The "register gets trashed" trap:

Assembly beginners stumble inevitably over the phenomenon that registers "suddenly" change their values,

although there is apparently no reason for such magic changes. Here is a short explanation why.



trashable, used e.g. for returning values



general purpose protected register



general purpose trashable register


source index

general purpose protected register, used e.g. in lodsd, movsd


destination index

general purpose protected register, used e.g. in stosd, scasb


base pointer

used for handling LOCAL variables - don't touch


stack pointer

used for push & pop and passing parameters - don't touch

* protected register (ebx, esi, edi, ebp):

1. If you use one of these registers, you must save it on entry into a proc, and restore it before the ret
   (you should avoid using ebp, as it is used for LOCAL variables; if you use LOCALs, do not use ebp explicitly, and do not save it)

2. an invoke GetTickCount or similar call of a Windows API will not change the protected register

* trashable register (eax, ecx, edx):

1. you can do whatever you want with this register

2. Windows will do whatever it wants with this register, so (most frequent noob error...!)

do not assume that e.g. ecx still has the same value after (for example) an invoke MessageBox, ...

3. macros of the print "Hello" type are calls to Windows APIs and will therefore trash these registers

Note that if you use only MasmBasic macros such as Open "O", #1, "MyFile.txt" or Print Str$("eax=%i", eax), the ecx register

will not be trashed; and you are not even obliged to save it.

For more detail, search Masm32 for ABI or see Register Preservation Convention in \masm32\help\asmintro.chm

- The LOCAL variables trap: They will contain garbage, so you must initialise them if you want zeroes:

MyTest proc argText:DWORD, argTitle:DWORD

LOCAL LocVarA:DWORD, LocVarB, pt:POINT, LocBuf[260]:BYTE

; ClearLocalVariables

; in MasmBasic, you can clear all local variables with one instruction

mov LocVarA, 0

; clear the first local variable

and LocVarB, 0

; and .. 0 has the same effect but is three bytes shorter: 4 instead of 7 bytes

and pt.x, 0

; and 0 clears the two DWORD

and pt.y, 0

; members of the POINT structure

mov LocBuf, 0

; a nullbyte delimits a string, so this "clears" the whole buffer

invoke MessageBox, 0, argText, argTitle, MB_OK



MyTest endp

- The .if eax<0 trap:

This is another trap for beginners...

mov eax, -1

.if eax<0

    MsgBox 0, "Eax is less than zero", "Hi", MB_OK


    MsgBox 0, "Surprise, surprise: eax is NOT less than zero", "Hi", MB_OK


The reason is simple: Registers are by definition unsigned integers. After a mov eax, -1, the register contains the

value 0FFFFFFFFh, decimal 4294967295 - and that is indeed a number way above zero. To achieve what you want

with .if eax<0, use .if sdword ptr eax<0 - this ensures that the register will be interpreted as a signed integer.

In MasmBasic, you can use .if signed eax<0 - the keyword signed is a simple equate for sdword ptr.

- The Console app trap

You assemble, link and run this code, and nothing happens:

include \masm32\include\



   inkey "Masm32 is so easy!"

   invoke ExitProcess, 0

end start

You try again, and the assembler complains about "fatal error: access denied"...

The reason is that if applications use e.g. print or inkey, they need a console window. The linker provides this

console window if it finds /SUBSYSTEM:CONSOLE in the command line. In some IDEs, you therefore need to use

"Console assembly and link", otherwise the application hangs. Note RichMasm autodetects whether your app

needs console or Windows mode, so simply pressing F6 ensures you get the right subsystem.

- Are 16 bits enough?

No, not really. 16 bits under Windows are obsolete. Strangely enough, some beginners still come to the Forum with 16-bit code snippets. Only if you have a compelling and absolutely plausible excuse for avoiding modern 32-bit code, search the web for masm 16-bit linker, and then go straight to the Masm 16-bit sub-forum.

- Are 64 bits better?

Only if you are running big servers, or working with 20,000*25,000 pixel images. Jumping from 16 to 32 bits was a quantum leap, sure (remember that 640k limit?); but apart from a handful of niche cases, there is practically no gain from using 64-bit code. It is often slower, also because it occupies more space in the instruction and data caches.

- Last but not least: A few Rules for the Forum

* Use include \masm32\include\, not include C:\masm32\include\; many people have installed Masm32 on a different drive, and it's a real nuisance having to replace C: with D: to test a code snippet

* To allow others to test your code, do not use environment variables for your paths. Masm32 has a hard-coded path structure, for good reasons.

* Post your complete code. Some believe that older members are eager to construct the missing headers around your snippets, but this belief is FALSE

* Formulate precise questions, provide precise error messages and error lines. You will get quicker and better answers

* Have fun with Masm, and enjoy the friendly atmosphere at the Masm32 Forum!