A styleguide and resource list for the Microsoft Assembler (MASM)
Taylor Bockman 1b9e172948
Update README.md
1 year ago
LICENSE Initial commit 1 year ago
README.md Update README.md 1 year ago

README.md

MASM Styleguide and Resource List

The Microsoft Assembler (MASM) is a popular assembler for Windows platforms. Unsurprisingly, there has been very few notable projects in MASM in the last decade.

Small, fast code just isn't as important as it used to be. Still, it is a very interesting exercise to learn MASM and use it. It's difficult to get binary sizes smaller than you can with raw assembly. Additionally, if you're in the world of reverse engineering, programming in assembly keeps your languages consistent.

Table of Contents

  1. Getting Started
    1. The Assembler
    2. IDEs
    3. VIM Plugins
    4. Visual Studio Code Extensions
  2. Tutorials
  3. Styleguide
    1. Tabs vs. Spaces
    2. Line Length
    3. Commenting
    4. Include Ordering
    5. Case Sensitivity
    6. Section Names
    7. Variable Names
    8. Functions
    9. Macros
    10. Function Prototypes
    11. Section
    12. Type Declarations
    13. Alignment
    14. Project Organization
    15. Mnemonics

Getting Started

You'll want to get some development tools. Of course, it goes without saying: you're going to need some flavor of Windows to run this stuff. Once you've configured Windows, you will need the assembler and optionally an IDE.

The Assembler

The most popular variant of MASM is MASM32 SDK. It's more or less an all in one package for coding assembly programs on Windows. One caveat - you'll need Windows 2000 or greater. This guide will focus on MASM32 primarily. Suggestions here should be easily ported to other variants.

IDEs

Thanks to the popularity of MASM, there are a couple IDE choices if you choose to go the route of using one. They are helpful, in that they handle assembling and linking for you. However, it's honestly something you can handle with a script.

WinAsm Studio

WinAsm Studio is arguably the most popular IDE for writing assembly code on Windows (as far as I'm aware). As it stands, I've had difficulty creating a new account on their forum to download the IDE. Unfortunately, they "account wall" the download so if you can't make a forum account, you won't get the download. (It's quite silly.)

VisualMASM

VisualMASM is another popular IDE. It's tailored to MASM and has the look and feel of a modern IDE. The most frustrating aspect is that there's no option to create a blank project. So if you're using a template, you're going to need to delete the base code that comes with the project to start. I have an issue on the VisualMASM repo in GitHub to address this.

VIM Plugins

VIM has pretty good support for assembly programming out of the box. I couldn't find any plugins that made programming any easier.

Visual Studio Code Extensions

x86 and x86_64 Assembly seems to be the most popular extension for Visual Studio Code when it comes to developing in assembly.

Tutorials

The most popular set of tutorials for MASM32 is Iczelion's Tutorial Series. There is a .CHM version of these tutorials available on the WinAsm website.

Styleguide

The styleguide is a work in progress. As I find more pretty ways to write assembly code I will put them here. I've realized over my time writing MASM code that every developer does things differently. This makes it incredibly frustrating to try and read another developer's code.

PS: It would be really cool if someone wrote a linter that checked for these things. Maybe I'll get around to it one of these days.

Tabs vs. Spaces

TODO

Line Length

Prefer 120 characters. MASM has a hard limit of 255 characters per line according to this post on MASM Forum. Many times prototypes and function invocations can have very long line lengths. For these, use \ to split your code across multiple lines.

Commenting

TODO

Include Ordering

As a matter of style, .inc files should be ordered system includes first and then project includes separated by a single blank line.

Sort them alphabetically, and separate them by a single blank line.

Example:

include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
include \masm32\include\windows.inc

include projectinclude.inc

includelib \masm32\include\kernel32.lib
includelib \masm32\include\user32.lib

Case Sensitivity

Always use the option casemap: none option. This prevents the assembler from thinking MyFunction is the same as myfunction, which will save you a lot of headaches.

Example:

.386
.MODEL flat, stdcall
option casemap: none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc

includelib \masm32\lib\kernel32.lib

.DATA
.CODE
  start:
    invoke ExitProcess, 0
  end start

Section Names

Prefer uppercase section names. This will help differentiate them from the rest of the code at a quick glance.

Example:

.386
.MODEL flat, stdcall
option casemap: none

include \masm32\include\windows.inc
include \masm32\include\kernel32.inc

includelib \masm32\lib\kernel32.lib

.DATA
.CODE
  start:
    invoke ExitProcess, 0
  end start

Variable Names

TODO - Once this is clarified, be sure to update any variable names in every section to reflect this change.

Functions

When writing functions, indent the body of the function so it is easily differentiated from other code levels.

Example:

   WinMain proc hInst: HINSTANCE, CmdLine: LPSTR, CmdShow: DWORD
    ; Code goes here...

    Ret
  WinMain EndP

Additionally, place your functions toward the bottom of your code section, or in an include file. This keeps your actual code uncluttered, and all of your functions in one easy-to-find place.

Macros

Similar to functions, indent the body of the macro so it's easily differentiated from other code levels. To keep code uncluttered, keep macros in an include file.

For macro "arguments", separate them like you would function arguments:

TEST macro x, y, z
 ;...
endm

Function Prototypes

In order to allow the use of functions at the bottom of your code, you need to declare function prototypes above the invoking code.

Place prototypes after all includes, and leave two empty lines between the includes and prototypes. Alternatively, store them in an include file to keep them out of your main body of code entirely.

Example:

include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
include \masm32\include\windows.inc

includelib \masm32\include\kernel32.lib
includelib \masm32\include\user32.lib


WinMain proto :DWORD, :DWORD, :DWORD, :DWORD

Function Arguments

Whether you are calling a function or writing an implementation, make sure to put a single space after each comma delimited argument.

Example:

  WinMain proc hInst: HINSTANCE, CmdLine: LPSTR, CmdShow: DWORD

Sections

In order to improve readability, indent the code in each section one level to differentiate it from the section name. This makes it so, when combined with all uppercase section names, it is easier to distinguish where you are in the code.

Example:

.CODE
  start:
    invoke ExitProcess, 0
  end start

Type Declarations

Put one space after the : in an argument's type declaration in order to improve readability. This goes the same for local variable type declarations.

Examples:

  WinMain proc hInst: HINSTANCE, CmdLine: LPSTR, CmdShow: DWORD
    LOCAL wc: WNDCLASSEX
    ; ...

Alignment

Prefer to keep type declarations and instantiations aligned.

Example:

.DATA 
  ClassName   db "WinClass", 0
  AppName     db "Window", 0

.DATA?
  hInstance   HINSTANCE ?
  CommandLine LPSTR     ? 

Project Organization

TODO

Mnemonics

When using assembly mnemonics, separate each argument with a space.

Example:

xor eax, eax
shl ebx, 8