This article provides a simple example on how to write a small program in x86 assembly language. The technologies used will be MASM (the Microsoft Assembler now distributed with Visual Studio) and Microsoft Visual Studio 2010 or Visual Studio 2012. Assembly programs offer the advantage of speed and full control over things that in other programming languages you cannot even touch. The example is a very simple example of basic text encryption and entails all basic assembly commands that one can use to start dealing with the magical realm of low level programming. And knowing how the computer responds at that level is crucial for someone who wants to be a programmer. Again, the main advice is one: EXPERIMENT! Try various commands you find in MASM manuals, change commands on your own, play with the memory and the registers.
Programming in Assembly
Programming in Assembly means telling the computer how to do things in a much more detailed manner than you would do with a High Level Programming Language (like C++).
I have written a small introduction to assembly here . For the purpose of this small tutorial, I am using as an example a simple encoding/decoding program (HuoCodec) which I distribute in the Download Files section of this article (and which is explained in more details here) . This program accepts input from the keyboard (letters and numbers typed by the user) and "encodes" it by just adding a value to the ASCII code value of the typed letter.
Assembly basics explained
Assembly has everything to do with memory. Most of the time, you will have to move data from one place (register) of the memory to another place in the memory. This is conducted with the
mov command. For example, the command...
mov AscChar, al
...moves the contents of the
AL memory register to the memory segment representing variable
AscChar (this is the variable which holds the character entered by the user).
You can also conduct operations on memory, like for example, adding a value to an existing value stored in the memory. The command...
add al, 2
2 to the contents of the
AL memory register. This is the "key" with which we "encrypt" the text entered by the user. In this case, when the user enters '
a', the program will show '
c' in the screen (since it will have added
2 to the ASCII value of the '
a' the user entered).
The flow of an assembly program can be controlled by comparing two values with the
cmp al, 5
...and then reconvert the flow where we want depending on the result of the comparison. For example, when we want to jump to point '
endLoop' (which denotes the end of the program by putting a label with that name in the code) if
AL is equal to
5, then we use the
je (Jump if Equal) command:
The respective part is commented out in the code distributed. You can experiment on your own and see what happens in case you put other similar commands in the code, like
jz (Jump if Zero).
DECRYPTION EXPERIMENT: In case you want to decrypt a message encrypted with that program, just create a new program with
-5 (instead of
5) added to the
The Microsoft MASM Assembler has embedded some ready-made functions that can be used to perform specific tasks. For example, in order to get the character entered by the user in a command line window, we invoke the
crt_getch function in our project:
Similarly, when we want to print out something on the screen, we use the
invoke StdOut , offset AscChar
EXPERIMENT: Find out for yourselves what the
Locate function does.
IMPORTANT NOTE: You have to include the related MASM libraries in your project in order to use the above mentioned functions. In this project, include the masm32rt.inc file in the \masm32\include\ folder as it is stated in the '
include' statement of the source code (it is distributed with MASM and you will also find it in the zip file from this site).
How to Use VS2010 to Write Assembly
Using Visual Studio to write an assembly program may be tricky. Specific steps are to be followed in order to be able to create your first MASM x86 assembly program with VS2010 / VS2012 (images from the configuration steps mentioned below are taken from here):
Expand the ‘Other Project Types‘ tree, Select ‘Visual Studio Solutions‘, and create a new ‘Blank Solution‘.
File | Add | New Project…
Expand the ‘Other Languages‘, ‘Visual C++‘, ‘General‘ section and create a new ‘Empty Project‘.
Now right click on the Project in the Solution Explorer and select ‘Build Customizations…‘.
Tick the ‘masm‘ box and say OK.
Add a new file to the project with the .asm extension by right clicking on the Project in the Solution Explorer and selecting ‘Add | New Item…‘ then ‘Text File‘. Enter a filename ending with .asm (e.g. test.asm). Press OK.
Now (and if you skipped the last steps, this won’t work) right click on the Project and select ‘Properties‘. You should see a dialog like this (Note the MASM item at the bottom of the tree). If you don’t, then something went wrong.
There are a few critical things to set up in the Linker options in order to get it to work:
Set the following property to Windows or Console as appropriate:
Configuration Properties > Linker > System> SubSystem
Set the entry point to the name of your main method (as per the END directive – see code):
Configuration Properties > Linker > Advanced > EntryPoint
All you have to do now is write some code and run it.
Visual Studio 2012 and MASM
The things mentioned above also apply to Visual Studio 2012. You must also define Configuration Parameters for your project as shown in the picture below.
I transfered the Huo_MASM_7 application from VS2010 to VS2012 and it worked perfectly with alsmost no issues. I say "almost" because the only thing I had to change was the SAFESEH compile parameter which had to change in NO for the program to sucessfully compile, as seen in the figure below.
Other than that, the program compiled and worked perfectly.
x86-64 Bit Assembly Programming
The x86-64bit assembly language extends the 32 bit registers and also has some new ones. So it has, for example, rax and rcx which are the 64-bit versions of the eax, ecx 32-bit registers. It also defines 8 new registers (r8, r9, etc) and the 32-bit versions of these registers (r8d, r9d). You then "just" have to use these registers to play with 64 bit assembly programming. The important thing to know is that what you did with the stack (with push and pop commands) in previous 32-bit assembly programs, you have to do it only via registers in 64 bits. This could mean that porting a 32-bit program to 64 bits could be more complex than you thought it would be.
In more detail, the main changes regarding the registers in 64 bit x86 assembly are:
- The EAX, EBX, ECX, EDX, ESI, EDI, EBP and ESP "general purpose" registers are all enlarged to 64-bits. The enlarged registers are accessed using RAX, RBX, RCX, RDX, RSI, RDI, RBP and RSP.
- You can still access the low dword of these registers (i.e., the least significant 32 bits) by using the existing names EAX, EBX, ECX, EDX, ESI, EDI, EBP and ESP.
- Eight (8) new registers are defined : r8, r9, r10, r11, r12, r13, r14, r15. The 32-versions of these registers are : r8d, r9d, r10d, .... The r8w, r9w, ... are the 16-bit variants (the low word) for these new registers and r8b, r9b, ... are the 8-bit variants (the low byte).
You have to have a tool to compile code for 64 bit. Possible tools to use include MASM 64-bit (search your PC for the ml64.exe file, which is usually packed with every Visual Studio) or GoAsm (see Internet references below).
MASM Resources in Internet
One can find more on assembly programming with MASM on the following sites:
32 bit Internet resources
64 bit Internet resources
- http://www.godevtool.com/GoasmHelp/64bits.htm#easy [GoAsm]
- Initial tutorial version posted: 2011-10-21
- Article updated: 2011-10-26
- Article updated: 2012-09-20