T80 & Win32 Assembly...
Introduction
This page is dedicated to the MASM32 package by Steve Hutchesson. MASM32 (current version is 8.0) is the Microsoft MASM assembler bundled with a good collection of tools to make writing Win32 applications in ASM easier to learn.
If you can understand Win32 C/C++ source code, learning to code Win32 applications in ASM will be relatively easy, because Win32 code in "high-level" ASM looks like code in C/C++. Of course, this applies only if the Win32 code is written in "plain" C++ (using the Win32 API) and not via Microsoft Foundation Classes. (MFC) ;)
Advantages of ASM
Two main reasons why ASM is still being used for writing applications today.
- If you write an entire application in "low-level" ASM, you can be sure that the assembled code in the executable will be almost similiar to your source code. That's one of the reasons why ASM is faster than other languages. Assembling an application is also a lot faster than compiling the same application written in C/C++.
- The assembled executable will very small in size. Even if you pack a compiled C/C++, Visual Basic, Delphi executable, the final size probably still be tens or hundreds of times larger than an assembled executable.
If you use MASM as your assembler, you will find that :
- MASM makes ASM coding in Win32 simpler than C/C++ : If you see C/C++ code, you will notice a lot of type-casting to many different such as abstract data types such as LPVOID, LPSTR and so on. MASM32 simplifies this by pre-defining such data types as generic types like BYTE, WORD, DWORD. Since Win32 API functions generally accept only 32-bit (DWORD) arguments, you only have to remember whether it takes in a value or address to a variable.
- MASM supports several high-level structures such as if-else-endif, while loops and so on. Of course, if-else-endif and while loops can be implemented in "low-level" ASM but using this approach to write complex conditional testing may be very error-prone and tedious to maintain.
Disadvantages
Of course, every programming language has its pros and cons and ASM is no exception.
- ASM takes more time to code. Actually it takes roughly the same amount of time if you were to code the same application in C/C++ but when rapid development (e.g prototypng) is required, Visual Basic or Delphi is probably the fastest way (if the size and/or speed of the executable is not a limiting factor).
- ASM is not portable. Unlike C/C++ or Java where code can be ported across platforms from Linux, Unix to Macintosh and so on, ASM cannot be ported. .
- Unlike high-level languages, where a lot of library functions are provided to simplify coding, MASM32 and probably other assemblers, don't have extensive collections of libraries so you have to rely on yourself to code required functions or use the Win32 API functions.
Tools
To write applications in Win32 ASM, you have to get some tools first.
- You'll need an assembler package, such as MASM32 to assemble and link your source code into an executable.
- A debugger. MASM32 now comes with VKDebug but I'm used to using the excellent OllyDbg by Oleh Yuschuk.
- A Win32 API reference.
- Tutorials and example code in ASM. Not necessary if you have exprience with the Win32 SDK but it's a good way to get coding quickly. Iczelion's tutorials are highly recommended.
Tips to optimize code for performance
This section contains mainly common sense stuff (to remind myself) as well as a record of my own experiences.
- For moving and manipulating of data, especially for strings, try to do it with DWORDs instead of BYTEs. This will improve performance a lot if you write it correctly.
- Try not to modularize all code into functions. Some code can be written as macros instead to minimize stack usage associated with calling functions
- If you cannot overuse a function, try optimizing it ;)
- Use registers a LOT. Register access is the fastest and using registers is much more efficient than using memory locations declared in the .data and .data? sections (global variables as in C/C++).
- If you cannot use registers, use local variables. Not as fast as registers but faster than global variables. Declare local variables in MASM with the .LOCAL macro
- Learn your logical instructions such as xor, and, or. For example, instead of doing an if-else-statement to set eax from 1 to 0 and vice versa, use xor eax, 1 instead.
- When multipling/dividing a number by powers of 2, use shl/shr respectively
- When manipulating strings, set the directional flag (DF) with std to start from the end of the string. Just remember to clear DF with cld after use and to move stringAddress+stringLength instead of just stringAddress to edi or esi. Useful for searching for the last '\' in a filepath to extract a filename.
Tips to optimize code for size
This section contains stuff gathered from my own experiences in Win32 ASM coding. Optimizing code for size is a lot easier than for performance, but the benefits may be quite neglible since assembled code is already vey small and besides, packers do the same job better.
- Declare unitialized buffers for string manipulation, file reads/writes in the .data? section to minimize exe size.
- Don't overuse macros. Overusing macros which you don't have the sourcecode can lead to bloated code when assembled.
- Use IF (without the period in front) and other conditional assembly macros when creating macros where the expression can be evaluated at compile time