Introduction to True Programming -
The Assembly program
These days it is difficult to differentiate between programming and scripting. Since the introduction of protected operating systems, it is no longer possible to access a computer’s hardware and send instruction to the processor directly. This is beneficial to most of the population, reducing virus infection, corruption and other malicious intent. Now we tend to do things through the .NET framework, both a curse and a gift.
For the sake of education, I thought it may be interesting to write a program in
Assembly (ASM) to experience the true aggravation of programming. Because it was difficult for me to find the resources I needed to embark on my journey, I felt that it may be beneficial to others to document the process of learning assembly.
Inline Assembly
Inline assembly is the easiest way to get a taste of what assembly can do. Inline assembly is a method of including assembly into another program. You will not have hardware access, but you will be able to use most of the basic commands. This will also help you down the line if you plan on writing your own operating system. You will always want to do most of your work in C or C++ if you are writing your own OS because ASM is difficult to interpret and not well structured. To save time and frustration, it is best to use ASM only where needed. So here is what we will need to start a basic inline assembly program:
Visual studio 2008 (installed and ready to go)
NASM or MASM (MASM is loaded by default)
Patience
Setting up The Project
A computer capable of running visual studio 2010
For this example I will be using the full version of visual studio. Feel free to try the express editions, but I have not tried to do inline assembly using that version.
First we will want to open visual studio and create a new project:
For the next step, your screen may appear differently if you have setup visual studio to create C# or C++ applications by default. If you have selected any other language other than C++ as your default, then you will find the C++ project under other languages.
It will be important to setup the project as a C++ project because Visual Basic and C# do not support inline ASM to my knowledge.
Don’t know C++? Don’t worry! There is no better way to learn! We will only graze the basics of C for now.
Go ahead and create a new empty C++ Project and name it something like InlineASMTest.
Now that your project is created, you may have to close the start page. If you don’t know what this is, it is the page shown in the first step. In the upper right corner, you will see a small X used to close the start page.
We are ready to create our first C program file. To do this, go to the solution explorer on the right side, then right click the top most element (your project), and then hover over Add and then select New Item.
Next we will want to specify the file type. Here we are going to simply create a text file, and name it Main.c. This will let visual studio to not import anything and let us make it from the ground up by ourselves. This will result in a much cleaner program than creating a CPP file.
We now have a nice clean blank canvas to work with, isn’t that nice!
With this program, we know we will want some simple output text, so we will need to import stdio.h. This is a standard input output library. Even though we are working in assembly, we will need to reference a prebuilt library to display some text. Later we will do away with this when we are no longer programming for a windows environment. We will also want to create our main function:
#include <stdio.h>
void
main() {
}
We now have a main function ready to have some code placed into it. If you are not familiar with C, the curly brackets specify the beginning and end of the statements that make up the function. This will become clear soon.
The next step is to create a basic output to test our function. We will use some basic commands to show that the main procedure is working.
#include <stdio.h>
void
main() {
printf(
Hello World ) ;
}
Now we can run our program by clicking the play button on the top toolbar, and
you should see your console window pop up and display the text.
Was that too fast for you? The window closed because the program ended. If you want the program to stay up long enough for you to see the text, then you should be sure to press Ctrl+F5 to run your code.
Now it is time to get down to business. We want to write a small program to add two values for us, and then display the value. For the sake of this tutorial, we will use ASM to do the addition. First we will write the program in C to get the basic Idea. Go ahead and make the necessary changes to your main function so that it looks like this:
#include <stdio.h>
void main() {
int a;
int b;
int c;
a = 2;
b = 4;
c = a + b;
printf( "Result: %i \n", c );
}
This is a very basic program. It initalizes three variables, sets a value to ‘a’ and ‘b’ then adds them together and stores them in C. This isn’t really what we’re after here, but it lays out the foundation for where we will put our ASM code. We will want to replace the addition segment with our ASM segment.
Before we continue, we should discuss a few important ASM commands.
MOV dest, src
ADD dest, value
You can see both commands take two parameters and are very simple in function. We can access any variable in C as if it were created in ASM. There are some limitations to where you can move values.
We should note that when using the MOV command, we are only able to move values into a register that can receive it. If you violate this rule, you will receive
an error.
“mov a, c” will produce the following error:
Error C2415: improper operand type
This is because the variable ‘a’ is not able to receive a value from variable ‘b’ directly. To accomplish the task, we will need to move the values into a register. This is a memory location in the processor that can hold a number or data. In our case, we will use one of the general registers. For x86 windows programming we have available to us memory locations with the following names:
EAX
EBX
ECX
EDX
Although there are many registers, we will start with these first. So EAX and EBX will be the locations we will move our data to for the addition. Later you will find that in some situations, it is first necessary to put a specific value into a specific register before preforming a function. Don’t worry too much about that now, because we will not need to use that until the next segment. So let’s try to move a value! To do this we will want to first setup our ASM segment and remove the addition (c = a + b;) and change it to simply zero out the C variable:
#include <stdio.h>
void main() {
int a;
int b;
int c;
a = 2;
b = 4;
c = 0;
__asm {
}
printf( "Result: %i \n" , c );
}
Now between the brackets, we can begin to add our assembly code. Let’s just assign a simple value to C. To do this we will use our MOV command, and not an equal sign:
#include <stdio.h>
void main() {
int a;
int b;
int c;
a = 2;
b = 4;
c = 0;
__asm {
mov c, 10
}
printf( "Result: %i \n", c );
}
Now hit Ctrl+F5 and look to see if you received the correct output. If you see the result is 10 then you successfully wrote your first ASM program! Now let’s try something different. We will attempt to use one of our general registers to store a value, and then pass the value it to another variable. Because we cannot simply move the variable from ‘c’ to ‘a’, we will use a general register EAX to hold the value temporarily. We will also add to our printf command to display all three variables. We are now going to introduce comments into the program. This is a line or text that is for humans to read only. Almost every programming language has this feature to help document what is happening in the code, an unfortunately, most programming languages have a different way to specify that the test will be ignored. See the example below:
#include <stdio.h>
void main() {
int a;
// This is a C comment
int b;
// everything after the // is ignored by the compiler
int c;
// This is used for letting others know what our program is doing!
a = 2;
b = 4;
c = 0;
// b = 200;
__asm {
; This is an ASM comment
; I will explain every line in the code
; and the compiler will ignore what I write.
mov c, 10
; Move 10 to C
mov eax, c
; Move the value of C to EAX
mov a, eax
; Move the value of EAX to A
}
printf( "Result: a = %i, b = %i, c = %i \n",a,b, c );
}
Now run your program again and see if you get the expected output. If you see that A = 10 then your program has run correctly, if not, check over the code and make sure nothing is missing. We successfully moved the value in C to the EAX register, and then moved the value of the EAX register to A. Also note that the line “// b = 200” was ignored by the compiler and the value of B remained 4.
Getting back to the math
Ok so now we have the basics of how to move variables around in ASM. Let’s rework this program to use the ADD command to do our addition for us. Remember, like the first program, we will want C to equal A and B. You will notice that the ADD command doesn’t simply take two parameters and then add them together. It takes a number and adds it to a register. We will need to move a number into the register, then add the value of another variable, then assign C to equal the value of the register we added to. Where we would normally see a single line for addition, we will need to break it up for ASM. Below is a pseudo code example of this:
The very simple math:
Z= X + Y
Will now be:
ADD X, Y
MOV Z, X
Notice how we need to move the value of X to Z. This is because X will be the starting value prior to the addition, and after the addition it is the sum of the two values.
We will write this out using real ASM now and using our registers. And remember, data seems to always move from right to left in ASM.
#include <stdio.h>
void main() {
int a;
// This is a C comment
int b;
// everything after the // is ignored by the compiler
int c;
// This is used for letting others know what our program is doing!
a = 2;
b = 4;
c = 0;
// b = 200
__asm {
; This is an ASM comment
; I will explain every line in the code
; and the compiler will ignore what I write.
mov eax, a
; Move the value of A to EAX
ADD eax, b
; Add the value of B to our EAX register
mov c, eax
; Move the value of EAX to C
}
printf( "Result: a = %i, b = %i, c = %i \n",a,b, c );
}
Now run your program and check your output. You should see the values of A, B, and C all adds up correctly. You may also want to try changing some values and making sure things still add up. Please note that we have not set up the ASM to handle longs or decimals. You can go ahead and try to add a decimal and then run the program. You will find that the decimal point is simply ignored.
Breaking out the ASM
For the final step of this section, we will take the ASM out of out of our main and make a nice function to handle our addition. We will need to first create the function that will hold our ASM code. You will need to enter the code for the new function after the ending curly bracket (“ } ”). A function is added as shown below:
int Add(int value1, int value2) {
return 0;
}
You may notice that this differs from the main function in that we now have 2 parameters in the parenthesis named value1 and value2. These are the parameters that will be sent to our function. The “int” represents integer, letting our program know that only integers can be passed into the function.
The Return keyword will make our function return the value to the right of the statement. For now we are setting the return value to 0. Now we will want to add out ASM code with some modifications as shown below:
int Add(int value1, int value2) {
int returnVal; // the value to be returned. Takes place of C
__asm {
mov eax, value1 ; Move the value of value1 to EAX
ADD eax, value2 ; Add the value of value2 to our EAX register
mov returnVal, eax ; Move the value of EAX to returnVal
}
return returnVal; // we will return the result of the addition
}
Now remove the ASM block from your main, and add a line to call the function:
c = Add(a,b);
Now we should have the final program:
#include <stdio.h>
void main() {
int a;
// This is a C comment
int b;
// everything after the // is ignored by the compiler
int c;
// This is used for letting others know what our program is doing!
a = 2;
b = 4;
c = Add(a,b);
printf( "Result: a = %i, b = %i, c = %i \n",a,b, c );
}
int Add(int value1, int value2) {
int returnVal; // the value to be returned. Takes place of C
__asm {
mov eax, value1 ; Move the value of value1 to EAX
ADD eax, value2 ; Add the value of value2 to our EAX register
mov returnVal, eax ; Move the value of EAX to returnVal
}
return returnVal;
// we will return the result of the addition
}
Now run the program, and you should see that everything once again adds up. You can continue to change different parts of the program to check the results. At this level, there is little you can do to harm your computer because you are in a protected environment, so feel free to experiment!
For our next section, we will discuss the stack, floating point processing, and dig deeper into the registers available to us. This will give us the foundation for setting up a program to run without an operating system.