The loop is one of the fundamental building blocks of any programming language and for assembler, this is no exception. What we are going to do in this tutorial is look at a simple loop, in the form of a do ... while loop. We shall build on the Hello World tutorial, and instead of printing the text 'Hello World', we will display the ascii characters 0 through to 9.
We shall be using four new instructions for this tutorial. These are
- mov - move data from a register to memory, memory to a register, or register to register
- inc - increment a register or memory location
- cmp - compare a register with memory, memory with register or register with register
- jb - the jump to location if the condition code flags show as below
; This is a console application that writes the digits 0 to 9 followed by ; a new line to the console and then exits global _mainCRTStartup ; This is the main program entry point extern [email protected] ; Windows API call to exit the process extern [email protected] ; Windows API call to get the standard output handle extern [email protected] ; Windows API call to write to a handle section .data ; Start of the data segment message db '0', 10 ; The ascii digit zero and a newline message bytes_written dd 0 ; Return 32-bit word from WriteFile handle dd 0 ; The standard output handle counter dd 0 ; Our loop counter initialized to zero section .code ; Start of the code segment ; We need to get hold of the standard output handle so we can write ; our text to it. This is provided by the GetStdHandle windows API call _mainCRTStartup: push -11 ; We want the standard output handle call [email protected] ; Call the Windows API GetStdHandle to retrieve it mov [handle], eax ; Save the handle for later use ; The start of our loop, and the position we return to if we want to ; print out the next digit start_loop: push 0 ; We do not want overlapped I/O push dword bytes_written ; The address of the number of bytes written push 2 ; The length of the text we are writing push dword message ; The address of the text we are writing push dword [handle] ; The handle returned from GetStdHandle call call [email protected] ; Write the text to the standard output handle inc byte [message] ; Increment the digit field inc dword [counter] ; Increment the counter mov eax, [counter] ; Load the counter value into eax cmp eax, 10 ; Compare the eax register with a value of 10 jb start_loop ; Jump back to the start of the loop if eax < 10 ; The text has been written, so all we need to do now is exit the ; process and return control back to the console push 0 ; Stack the exit code call [email protected] ; Exit the process
Note that the message string already contains the first ascii digit of '0', and our counter is also preset to binary zero. The first tweny-two lines are not that much different from the code provided in the Hello World tutorial, so we shall start immediately after the call to GetStdHandle. Here we introduce the first of the new instructions, the mov instruction. There are many forms of this instruction, but in the line
mov [handle], eax ; Save the handle for later use
we are moving the contents of the eax 32-bit register to the memory location known as handle.
The next line,
start_loop: [/code is a label and is the start of the loop, and the place which we shall return to provided we have not processed the loop more than nine more times. The next six lines [code] push 0 ; We do not want overlapped I/O push dword bytes_written ; The address of the number of bytes written push 2 ; The length of the text we are writing push dword message ; The address of the text we are writing push dword [handle] ; The handle returned from GetStdHandle call call [email protected] ; Write the text to the standard output handle
are outputting the two characters to the standard output - this is the single digit and the newline character.
The next two lines involve the use of the next new instruction inc, the first of the two lines
inc byte [message] ; Increment the digit field inc dword [counter] ; Increment the counter
adds one to the first byte of our two byte message, taking '0' to ascii '1', and the second line adds one to the memory location known as counter.
The next line,
mov eax, [counter] ; Load the counter value into eax
is a variant on the previous move instruction which loads the contents of the memory location known as counter into the eax register.
The next line,
cmp eax, 10 ; Compare the eax register with a value of 10
is another new instruction and compares the contents of the eax with the immediate value of 10 (an immediate value is actually encoded into the instruction stream, rather than being a location in memory. The results of the compare set bits in the condition code register which we can then go on to test.
Finally, we have the last of our new instructions which is the jb instruction tests the condition code flags to determine if the comparison resulted in a less than or below result (the instructions jb and jl are identical).
jb start_loop ; Jump back to the start of the loop if eax < 10
If the result is true, then the next instruction is at the location known as start_loop, otherwise the next instruction to be executed is the instruction following the jb statement.
Finally, the last two lines of code exit the process.
If you compile and run this code, you should end up with the following output on the console
0 1 2 3 4 5 6 7 8 9
The next tutorial is here.
This post has been edited by Martyn.Rae: 06 April 2010 - 08:57 AM