Page 1 of 1

MASM - Loops

#1 GunnerInc  Icon User is offline

  • "Hurry up and wait"
  • member icon




Reputation: 859
  • View blog
  • Posts: 2,307
  • Joined: 28-March 11

Posted 30 October 2011 - 12:23 PM

Looping is a fundamental part of programming repetitive tasks. Let's take the following pseudo-code:

1. Open fridge
2. Take out apple
3. Eat apple
4. Did I eat 10 apples yet?
4a. No, repeat 3
4b. Yes, close fridge and go relax now I am full.

3 - 4 would be a loop. How would we do that in Assembly? I will show you how using Assembly and using MASM "High Level" syntax

The CPU has an instruction for loops called loop, it has two requirement - a label to loop to and a counter, the ecx (Extended Count register) register is the counter for the loop instruction.
You would put the iteration count in ecx and loop will decrement ecx till it equals 0 then exit the loop.

Print* are debug macros included in the MASM32 package that will "print" to a debug window or the RadASM IDE output window.

This will print "Yummy Apple!" 10 times, exit the loop then print "I ate 10 apples, now I am full"
    mov     ecx, 10
EatRedApple:
    PrintText "Yummy Apple!"
    loop    EatRedApple
    PrintText "I ate 10 apples, I am full now"


Another way to do a loop is:
    mov     ecx, 10
EatBlueApple:
    PrintText "A blue Apple?!?!"
    dec     ecx
    test    ecx, ecx
    jnz     EatBlueApple
    PrintText "UGH, I ate 10 blue Apples YUCK"   


What we are doing is
1. Setting our counter to 10
2. Doing something
3. Decreasing our counter - dec
4. Testing to see if the zero flag is set - test (test does a bit-wise logical AND on the source and destination WITHOUT
5. If zero flag is not set jump back to EatBlueApple - jnz = Jump if not zero
5a. If zero flag is set, then leave loop

Yet another loop:
    mov     ecx, 10
EatGreenApple:
    PrintText "Green Apple, tart but yummy"
    dec     ecx
    jnz     EatGreenApple 
    PrintText "I ate 10 green apples, I have a tummy ache now"


This one is a little bit more optimized than the BlueApple loop, if we are decreasing our counter then when our counter is zero, the zero flag gets set so we don't have to compare/test for zero.

Incrementing counter loop:
    xor     ecx, ecx
RottenApple:
    PrintText "Oh no, not rotten Apples!"
    inc     ecx
    cmp     ecx, 10
    jne     RottenApple
    PrintText "Please no more rotten apples!"


We compare (cmp) our counter to 10 and if it is not 10 repeat RottenApple. jne = Jump if Not Equal. What cmp does in the CPU is subtract (SUB) the second operand from the first and sets ONLY the FLAGS registers.
Whereas the SUB instruction modifies the first operand.
So, this is what will happen:

Quote

dest > source then Carry Flag = 0 Zero Flag = 0
dest = source then Carry Flag = 0 Zero Flag = 1
dest < source then Carry Flag = 1 Zero Flag = 0

This is for unsigned numbers, signed numbers is a bit different.

Not to confuse you anymore than you are with Assembly, BUT... knowing what flags are set you can use different mnumonics with different encodings/sizes and for code readability.
So in the RottenApple, you could replace jne (Jump if Not Equal) with:
jnz (Jump if zero flag != 0) and have the same results.

So, what about using MASM and its High Level stuff? Ok, we will use 2 - a .while/.endw loop and a .repeat/.until loop. MASM has many HLL macros that make coding easier and cleaner looking, but I
wouldn't use them in speed critical loops, instead I would manually code a loop.
GreenApple loop with counter going 1 to 10
    xor     ecx, ecx
    inc     ecx
    .while ecx <= 10
        PrintText "Another apple"
        inc     ecx
    .endw


We will start the counter @ 1. Sure we could
    mov     ecx, 1

but that is 5 bytes, while
    xor     ecx, ecx
    inc     ecx

is only 3 bytes :)

So, we first set our starting index, check to see if our counter is at its max (10), if not, do something (printtext), increase our counter then jump to the beginning.

Another way is to use a .repeat/.until going 0 to 10
    xor     ecx, ecx
    .repeat
        PrintText "Ah jeesh another apple?"
        inc     ecx
    .until ecx == 10


A .while loop checks the condition at the beginning of the loop, while a .repeat/.until checks the condition at the end of the loop.

Can I "nest" loops? No, why would you want to do that? haha Of course you can!
    xor     ecx, ecx
    .repeat
        PrintText "Eating Apple"
        .while dwGreenApple <= I_AM_FULL
            .if dwGreenApple <=6
                PrintText "Yum, green apple"
            .else
                PrintText "No more apples please"
            .endif
            inc     dwGreenApple
        .endw
        inc     ecx
    .until ecx == I_AM_FULL


Those are all "simple" loops, they can get more complicated but using the HL syntax of MASM, it makes life easier.

Wait, wait... what is that .if/.else/.endif? Next tut folks, next tut :-)

Is This A Good Question/Topic? 0
  • +

Page 1 of 1