x86 Disassembly/Loops

From Wikibooks, open books for an open world
Jump to: navigation, search

Loops[edit]

To complete repetitive tasks, programmers often implement loops. There are many sorts of loops, but they can all be boiled down to a few similar formats in assembly code. This chapter will discuss loops, how to identify them, and how to "decompile" them back into high-level representations.

Do-While Loops[edit]

It seems counterintuitive that this section will consider Do-While loops first, considering that they might be the least used of all the variations in practice. However, there is method to our madness, so read on.

Consider the following generic Do-While loop:

 do
 {
    action;
 } while(condition);
C language do while.png

What does this loop do? The loop body simply executes, the condition is tested at the end of the loop, and the loop jumps back to the beginning of the loop if the condition is satisfied. Unlike if statements, Do-While conditions are not reversed.

Let us now take a look at the following C code:

 do
 {
   x++;
 } while(x != 10);

Which can be translated into assembly language as such:

 mov eax, $x
 beginning:
 inc eax
 cmp eax, 0x0A ;0x0A = 10
 jne beginning
 mov $x, eax

While Loops[edit]

While loops look almost as simple as a Do-While loop, but in reality they aren't as simple at all. Let's examine a generic while-loop:

 while(x)
 {
    //loop body
 }

What does this loop do? First, the loop checks to make sure that x is true. If x is not true, the loop is skipped. The loop body is then executed, followed by another check: is x still true? If x is still true, execution jumps back to the top of the loop, and execution continues. Keep in mind that there needs to be a jump at the bottom of the loop (to get back up to the top), but it makes no sense to jump back to the top, retest the conditional, and then jump back to the bottom of the loop if the conditional is found to be false. The while-loop then, performs the following steps:

  1. check the condition. if it is false, go to the end
  2. perform the loop body
  3. check the condition, if it is true, jump to 2.
  4. if the condition is not true, fall-through the end of the loop.

Here is a while-loop in C code:

 while(x <= 10)
 {
    x++;
 }

And here then is that same loop translated into assembly:

 mov eax, $x
 cmp eax, 0x0A
 jg end
 beginning:
 inc eax
 cmp eax, 0x0A
 jle beginning
 end:

If we were to translate that assembly code back into C, we would get the following code:

 if(x <= 10) //remember: in If statements, we reverse the condition from the asm
 {
   do
   {
     x++;
   } while(x <= 10)
 }

See why we covered the Do-While loop first? Because the While-loop becomes a Do-While when it gets assembled.

So why can't the jump label occur before the test?

mov eax, $x
beginning:
cmp eax, 0x0A
jg end
inc eax
jmp begnning
end:
mov $x, eax

For Loops[edit]

What is a For-Loop? In essence, it's a While-Loop with an initial state, a condition, and an iterative instruction. For instance, the following generic For-Loop:

 for(initialization; condition; increment)
 {
   action
 }
C language for.png

gets translated into the following pseudocode while-loop:

 initialization;
 while(condition)
 {
   action;
   increment;
 }

Which in turn gets translated into the following Do-While Loop:

 initialization;
 if(condition)
 {
    do
    {
       action;
       increment;
    } while(condition);
 }

Note that often in for() loops you assign an initial constant value in A (for example x = 0), and then compare that value with another constant in B (for example x < 10). Most optimizing compilers will be able to notice that the first time x IS less than 10, and therefore there is no need for the initial if(B) statement. In such cases, the compiler will simply generate the following sequence:

 initialization;
 do
 {
    action
    increment;
 } while(condition);

rendering the code indistinguishable from a while() loop.

Other Loop Types[edit]

C only has Do-While, While, and For Loops, but some other languages may very well implement their own types. Also, a good C-Programmer could easily "home brew" a new type of loop using a series of good macros, so they bear some consideration:

Do-Until Loop[edit]

A common Do-Until Loop will take the following form:

 do
 {
   //loop body
 } until(x);

which essentially becomes the following Do-While loop:

 do
 {
   //loop body
 } while(!x);

Until Loop[edit]

Like the Do-Until loop, the standard Until-Loop looks like the following:

 until(x)
 {
   //loop body
 }

which (likewise) gets translated to the following While-Loop:

 while(!x)
 {
   //loop body
 }

Do-Forever Loop[edit]

A Do-Forever loop is simply an unqualified loop with a condition that is always true. For instance, the following pseudo-code:

 doforever
 {
   //loop body
 }

will become the following while-loop:

 while(1)
 {
   //loop body
 }

Which can actually be reduced to a simple unconditional jump statement:

 beginning:
 ;loop body
 jmp beginning

Notice that some non-optimizing compilers will produce nonsensical code for this:

 mov ax, 1
 cmp ax, 1 
 jne loopend
 beginning:
 ;loop body
 cmp ax, 1
 je beginning
 loopend:

Notice that a lot of the comparisons here are not needed since the condition is a constant. Most compilers will optimize cases like this.