General program layout.
There are a few sections in an Assembly program:
This is where all of your initialized data goes. App strings, numbers etc... It takes up room in your exe i.e. if you initialize a 5000 byte array here, your exe will be 5000 bytes bigger.
This is where all of your UN-initialized data goes. String buffers, arrays, structures, variables etc... It DOES NOT take up room in your exe.
This is where you can put all values that don't change in your code, i.e. IAmTrue equ TRUE
This is where all your program code goes
Technically you can have 1 asm file with everything in it. I don't do that, I have a few files:
Main.asm - basic code is here
strings.inc - all predefined strings here
data.inc - all uninitialized data here
WndProcs.asm - all window procedures are here
protos.inc - protos for procs are here
equates.inc - equates are here
I will be referring to the MASM32 package in this tut. You can find a link to MASM32 in this tut. It contains C headers/libs from the SDK translated to MASM inc/lib files
A bare minimum exe:
.586 .model flat, stdcall option casemap:none include kernel32.inc includelib kernel32.lib .code BareApp: invoke ExitProcess, 0 end BareApp
.586 tells ML what mnemonics you want to use. Unless you are doing something exotic, .386 - .686 is fine
.model flat, stdcall tells ML we want the flat memory model. This is what all Win32 apps use. stdcall is the procedure calling convention we are going to use - The called proc cleans up the stack
option casemap:none tells ML variables, labels, proc names etc... are case sensitive meaning exitprocess and ExitProcess are two different things (helps cut down on bugs)
On a side note. If you wanted to get creative you could do: GoAway equ ExitProcess and instead of invoke ExitProcess, 0 you could do invoke GoAway, 0, you could even redefine registers. EQU is a cool tool.
Next is include, and includelib. the include directive tells ML to process kernel32.inc. This file contains the prototypes for the functions in kernel32.dll. IncludeLib tells the linker how to resolve proc names.
In MASM, you don't need a "WinMain" as your entry point. In the above sample, the label BareApp is the entry point, whatever you name it, you need a corresponding end labelname at the end.
Hey, that is all great and all but how do I make an exe after I type all my code?
Good question. There are many ways: batch files, nmake, make, IDE's, even text editors allow you to shell out to ML.
Here is a sample batch file from MASM32:
@echo off if not exist rsrc.rc goto over1 \masm32\bin\rc /v rsrc.rc \masm32\bin\cvtres /machine:ix86 rsrc.res :over1 if exist %1.obj del %1.obj if exist %1.exe del %1.exe \masm32\bin\ml /c /coff %1.asm if errorlevel 1 goto errasm if not exist rsrc.obj goto nores \masm32\bin\Link /SUBSYSTEM:WINDOWS /OPT:NOREF %1.obj rsrc.obj if errorlevel 1 goto errlink dir %1.* goto TheEnd :nores \masm32\bin\Link /SUBSYSTEM:WINDOWS /OPT:NOREF %1.obj if errorlevel 1 goto errlink dir %1.* goto TheEnd :errlink echo _ echo Link error goto TheEnd :errasm echo _ echo Assembly Error goto TheEnd :TheEnd pause
I use RadASM as my IDE, I just set a few paths and Assembling and linking is easy. BTW, we don't "compile" in Assembly, we Assemble and link. :-)
Before we get on to a sample app, let's go over a few things.
DOS and 16bit ASM use Interrupts to interact with the OS, screen, drives, files etc... Win32 Asm (Which we will be doing) uses the Windows API, so if you have experience with it that is a plus. MSDN will be your best friend or you can
download the SDK from microsoft (you can even get it on cd for free from MS, just pay shipping)
Variables: One thing I could never grasp in the HLLs are the MANY different variable types when there are only a handful the CPU uses - BYTE (1 byte), WORD (2 bytes), DWORD (4 bytes), FWORD (6 bytes), QWORD(8 bytes), TBYTE(10 bytes), REAL4(4 bytes), REAL8(8 bytes), REAL10(10 bytes)
For general Windows programming, you will mostly use BYTE, WORD, and DWORD. Naturally, 64bit adds a few others.
You may be tempted to use the smallest data type (BYTE) for something like a Boolean variable, but that will actually give you a performance penalty since memory is DWORD aligned, so use a DWORD for a Boolean variable.
Everything is basically a pointer to some memory.
Yes you can use COM in Assembly, it is far beyond this tut and is hair pulling at first.
I seen a lot of newbies over the years or people that use different Assemblers saying, I don't want to use the MASM high level stuff... bah, the .ifs, .whiles produce decent code. I say, use em at first until you get comfy with ASM.
A little info on Anti-Virus programs - THEY SUCK when writing in Assembly. They don't like the small code, the way sections are aligned, the order of certain instructions, whatever. Ways to shut them up -
include a manifest and a version block in your exe, re-order some instructions/API calls.
Next up - Creating our first app in Assembly!