Chapter 4 Notes

 

Overview

Programming is hard! The goal of much research in computer science is to develop methods that make programming easier and programs more reliable. One familiar method is structured programming which uses formal control structures (For, While, If, etc.) to control program execution. In Assembly language these control structures do not exist as part of the language but can be implemented using the techniques examined in these notes and the text.

First the details of execution control in Assembler.

 

Execution Control

Recall that the IP (Instruction Pointer) always points to the next instruction to execute, where the next fetch will occur. By changing the IP, different parts of the algorithm can be executed rather than the next sequential instruction. The following discusses the three forms of execution control available on the Intel processor.

 

Sequential, Unconditional, Conditional Execution
Corresponding Sequential, Unconditional, Conditional Code
   Mov  eAx, 0

   Call WriteDec

   Inc  eAx

   Mov  eCx, 4
   Lea  eDx, Done    
   Call WriteString




Output: 0 Done
   Mov  eAx, 0

A: Call WriteDec

   Inc  eAx

   Jmp  A

   Mov  eCx, 4
   Lea  Di, Done
   Call WriteString 


Output: 0 1 2 ...   
   Mov  eAx, 0

A: Call WriteDec

   Inc  eAx

   Cmp  eAx, 10
   JL   A

   Mov  eCx, 4
   Lea  Di, Done
   Call WriteString

Output: 0 1 2 ... 8 9 Done

 

Labels

Labels define unique names for points in the algorithm. In the following unconditional branching code, A: defines the label, the Jmp A instruction branches to that point in the algorithm. The code produces an infinite execution with Al = ...0, 1, 2, ..., 65534, 65535, 0, 1, 2, ...
 
A: Call WriteDec
   Inc  eAx

   Jmp  A

 

Jmp - Unconditional Branch

An unconditional branch or jump is an execution branch always taken. In the program fragment above the Jmp A causes execution to branch unconditionally to the label A:.

Recall that the IP always points to the next instruction to be fetched. The unconditional branch instruction is executed by changing the IP to the address of the label. Consider the following code which shows the effects on the IP of the unconditional Jmp A execution. The steps are:

 

  1. fetch instruction Jmp A at IP value, offset 0006,
  2. update IP to next instruction, offset 0009
  3. execute Jmp A by setting IP to 0002, the offset of the label A.

 

Before and After Execute of Jmp A
After Fetch/Before Execute

      0002    A: Call WriteDec      
      0005       Inc  eAx
      0006       Jmp  A
IP -> 0009       Call WriteDec
After Execute

IP -> 0002    A: Call WriteDec
      0005       Inc  eAx
      0006       Jmp  A
      0009       Call WriteDec

 

Cmp - Compare

Before examining conditional branching it is useful to first consider how to compare two values. It is common in programming to compare the relation of two values (>,<, !=, ==, etc.) which produces a true or false result. The Cmp instruction is a simple way to make such a comparison. Consider the following identical C++ and Assembler code:
 
C++ and Assembler to print 0 1 ... 8 9 Done
    eAx = 0;
A:  cout << eAx;
 
    eAx++;  

 

      if (eAx < 10) goto A

 

    cout << "Done";  


   Mov  eAx, 0

A: Call WriteDec

   Inc  eAx

 

    Cmp  eAx, 10
     JL   A

 

   Mov  eCx, 4
   Lea  Di, Done
   Call WriteString
Cmp versus Sub - Recall that the Sub subtracts producing a result but also setting  flags (CF, OF, SF, ZF). The Cmp instruction is identical to the Sub but only sets flags. To see the difference consider the following example noticing that the value of the Ah register changes with the Sub but not the Cmp.
 
Difference between Sub and Cmp
   Ah changes

   Mov  Ah, 00000101B = 5
   Sub  Ah, 00000010B = 2

   Ah = 00000011 = 3
   CF = 0 OF = 0
   ZF = 0 SF = 0
   Ah no change

   Mov  Ah, 00000101B = 5
   Cmp  Ah, 00000010B = 2

   Ah = 00000101 = 5
   CF = 0 OF = 0
   ZF = 0 SF = 0
Both set the flags which can now be examined to determine the relationship between two values, in this case 5 and 2. As an example, consider some of the possible relations between 5 and 2. Examine the Flag values column and compare with the flag values above to determine if the Condition column of the relation is true or false.
 
Possible relationships between 5 and 2
Relation Condition Flag values for Condition to be True
5 == 2 False ZF = 1
5 != 2 True ZF = 0
5 < 2 False CF = 1
5 > 2 True ZF = 0 and CF = 0
5 <= 2 False ZF = 1 or CF = 1
5 >= 2 True CF = 0

 

Je, Jne, Jl, Jg, ... - Conditional Branch

Conditional branching tests whether a condition is true, if true the branch to a label is made, otherwise the next sequential instruction is executed. In the following code the JL A instruction branches to label A in the algorithm if the condition Less Than is true. Otherwise the next instruction Mov Cx, 4 is executed.
 
A: Call WriteDec
   Inc  eAx

   Cmp  eAx, 10
   JL   A
 
   Mov  eCx, 4

 

 

Conditional JMPs
Unsigned Numbers
 Mnemonic Description Flags values for true condition C++ condition
JA/JNBE 
Jump if above
Jump if not below nor equal
CF = 0 and ZF = 0
X > Y
JAE/JNB
Jump if above or equal
Jump if not below
CF=0
X >= Y
JB/JNAE
Jump if below
Jump if not above nor equal
CF = 1
X < Y
JBE/JNA
Jump if below or equal
Jump if not above
CF = 1 OR ZF = 1
X <= Y
JE/JZ
Jump if equal zero
ZF = 1
X == Y
JNE/JNZ
Jump if not equal zero
ZF = 0
X != Y
 
Signed Numbers
 Mnemonic Description Flags values for true condition C++ condition
JG/JNLE 
Jump if greater
Jump if not less nor equal
ZF = 0 and SF == OF
X > Y
JGE/JNL
Jump if above or equal
Jump if not below
SF == OF
X >= Y
JL/JNGE
Jump if less than
Jump if not greater nor equal
SF != OF
X < Y
JLE/JNG
Jump if less than or equal
Jump if not greater
ZF = 1 or SF != OF
X <= Y
JE/JZ
Jump if equal zero
ZF = 1
X == Y
JNE/JNZ
Jump if not equal zero
ZF = 0
X != Y

 

Unconditional/Conditional Differences

Beyond the obvious difference that the unconditional jumps ignore flags and conditional jumps examine flags, one other important difference is the distance the jump can make. We'll use the following program fragment listing to illustrate the differences. Some minor changes have been made to the listing to make the example more clear.
 
Conditional and Unconditional Jump Example
     
     12 0005  74 09                          Je      A
     13
     14 0007  EB 00 10                       Jmp     A
     15
     16 000A  C7 06 0000r 000A               Mov     X, 10
     17
     18 0010  C7 06 0000r 000B         A:    Mov     X, 11
     19
     20 0016  C7 06 0000r 000C               Mov     X, 12
     21
     22 001C  74 F2                          Je      A
     

 

Problems - The problem that occassionally occurs is when a conditional jump is attempted that is too far from the destination label, beyond -128 to 127 bytes away. However, the unconditional jump can reach from 0 to 65535 bytes away. The solution to reach a label that is too far away for a conditional jump is to use a conditional jump to an unconditional jump to the label. Below is an example of the problem and a solution. The solution is not completely satisfactory since it requires us to invert the logic.
 
Solving the Conditional Jump Limit
Problem Solution
 A:

  More than 127 bytes

  Je   A
  Mov  X, 12 
A:
    More than 127 bytes

     Jne   Aa
     Jmp   A
Aa:  Mov  X, 12

 

Structured Programming

Structured programming abstractions have long been widely utilized to improve programmer productivity and program reliability. One of the key concepts at the foundation of the success of structured programming methods is the restriction of sequence control structures to:
  1. Sequential - The next sequential instruction is executed
  2. Iteration - A sequence of instructions are repeatedly executed for a specified number of iterations. Example: FOR, WHILE
  3. Conditional - An instruction is conditionally executed based upon a conditional expression being true. Example: IF
The defining characteristic of structured programming constructs is that of ONE ENTRY/ONE EXIT. Entry is only at the beginning of the structure; exit is only at the end; its importance is to limit the number of possible entries and exits to a section of code to exactly one. Most modern, high-level languages support structured programming concepts, languages such as Pascal and C++ provide formal syntax to describe the three sequence control structures listed above. Notice that the GoTo instruction is not considered a part of structured programming since it allows arbitrary entries and exits. Unfortunately the Intel machine architecture and the corresponding assembly language does not formally support structured techniques, having only the branch, or JMP, instruction, but disciplined program implementation can easily abstract the necessary control structures.

The following gives the general form of assembly instructions necessary to abstract common structured constructs. As a general programming rule, one should solve the programming problem first in a pseudocode language using structured methods then translate the pseudocode to a target language. This holds doubly true for assembly language as the myriad of details involved in simultaneously designing and implementing an algorithm directly in assembly can be overwhelming.

 

The figure below illustrates the advantage of good structure and naming conventions for improved readability and programming correctness.
 

 

Structured versus Unstructured - Absolute Value of X
Structured C++

  int X = -5;   

  if (X < 0)
      X = -X;

  X++;
Structure not obvious  

   Mov  X, -5

   Cmp  X, 0
   JGE  Positive  
   Neg  X
Positive: 
   Inc  X  
Structured but logic 
inverted 

   Mov  X, -5

if: Cmp  X, 0
    JGE  endif  
    Neg  X
endif: 
   Inc  X  
Structure obvious

    Mov  X, -5   

if: Cmp  X, 0
    JL   then
    Jmp  endif
then:
    Neg  X
endif: 
    Inc  X  

While

 Pseudocode                              Assembler

 WHILE Condition DO                      WHILE:    cmp  opr1, opr2
     statement;                                    jCondition DO
 ENDWHILE                                          jmp ENDWHILE      
                                             DO:
                                                       statement
                                                       jmp   WHILE
                                        ENDWHILE: 

 


Example:
 
 while (eCX > 5)                         WHILE:      cmp   eCX, 5
        eCX =  eCX - 1;                               jG   DO  
                                                     jmp   ENDWHILE
                                             DO:
                                                     dec   eCX
                                                     jmp   WHILE
                                        ENDWHILE: Example:

 


Example:

 while (eCX > 5  || AB != eCX)            WHILE:     cmp  eCX, 5
        eCX =  eCX - 1;                              jG   DO
                                                OR:  cmp  AB, eCX
                                                     jNE  DO
                                                     jmp  ENDWHILE
                                             DO:
                                                     dec   eCX
                                                     jmp   WHILE
                                        ENDWHILE:

 

 


If Then/If Then Else

Pseudocode                              Assembler

 IF Condition                            IF: cmp  opr1, opr2
  THEN statement1                            jCondition    THEN
  ELSE statement2                            jmp           ELSE
 ENDIF                                    THEN:
                                                statement1
                                                jmp        ENDIF
                                           ELSE:
                                                statement2
                                        ENDIF:  

 


Example:

 if (char == 'A')                              IF:  cmp  char, 'A'
 {                                                  jE   THEN
          al = char;                                jmp  ENDIF
          eCX = eCX + 1;                           THEN:
 }                                                  mov  al, char 
                                                    inc  eCx
                                                 ENDIF:              

 


Example:

 if (char == 'A' && eCX != 10)                  IF:  cmp  char, 'A'
 {                                                  jE    AND
          al = char;                                jmp   ELSE
          eCX = eCX + 1;                        AND: cmp  eCX, 10  
 }                                                  jNE   THEN
 else                                               jmp   ELSE
       eCX = eCX - 1;                             THEN:
                                                    mov     al, char
                                                    inc     eCX
                                                    jmp     ENDIF
                                                ELSE:
                                                    dec     eCX
                                               ENDIF:

For

Pseudocode                              Assembler

 FOR (Index = Start ;                        mov  Index, Start
      Index Condition Stop ; Index++)   FOR: cmp  Index, Stop
  DO statement;                              jCondition  DO
 ENDFOR                                      jmp  ENDFOR
                                          DO:
                                                  statement
                                                  inc  Index
                                                  jmp  FOR
                                        ENDFOR:

 


Example:

 for (eCX = 10; eCX <=15; eCX++)             mov  eCX, 10
     cout << eCX ;                        FOR:
                                             cmp  eCX, 15
                                             jLE  DO
                                             jmp  ENDFOR
                                         DO:
                                             mov  eAX, eCX
                                             call WriteDec  
                                             inc  eCX
                                             jmp  FOR
                                          ENDFOR:

 


Example:

 for (eCX = 10; eCX <=15; eCX++)  {           mov  eCX, 10
     cin >> eAX ;                        FOR:
     if (eAX < 0)                             cmp  eCX, 15
         eAX = -eAX;                          jLE  DO
     eDX = eDX + eAX;                         jmp  ENDFOR
 }                                        DO:
                                              call ReadDec  
                                          IF: cmp  eAX, 0       
                                              jL   THEN
                                              jmp  ENDIF
                                            THEN:  neg  eAX          
                                           ENDIF:
                                             add  eDX, eAX
                                             inc  eCX
                                             jmp  FOR
                                          ENDFOR:

Repeat

Pseudocode                              Assembler

 REPEAT                             REPEAT:
   Statement                            Statement
 UNTIL Condition                    WHILE:
                                        cmp  opr1, opr2
                                        jCondition ENDREPEAT
                                        JMP  REPEAT
                                    ENDREPEAT:

 


Example:

 REPEAT                             REPEAT:
     eCX := eCX - 1                     dec  eCX
 UNTIL (eCX <= 5) AND                UNTIL:
      (AB = eCX );                      cmp  eCX, 5
                                        jle  AND
                                        jmp  REPEAT
                                    AND:
                                        cmp  AB, eCX
                                        je   ENDREPEAT
                                        jmp  REPEAT
                                   ENDREPEAT:

Do While

Pseudocode                              Assembly

 DO                                      DO:
     Statement                               Statement
 WHILE Condition                         WHILE: Cmp opr1, opr2
                                                jCondition DO
                                        ENDWHILE:                   

 


Example:

 do                                 DO:
     eCX = eCX - 1;                     dec  eCX
 while (eCX <= 5 );                  WHILE:
                                        cmp  eCX, 5
                                        jle  DO
                                    ENDWHILE:

 


Example:

 do                                 DO:
     eCX = eCX - 1;                     dec  eCX
 while (eCX <= 5 &&                  WHILE:
       AB == eCX );                     cmp  eCX, 5
                                        jle  AND
                                        jmp  ENDWHILE
                                     AND:
                                        cmp  AB, eCX
                                        je   DO
                                    ENDWHILE:

 


 


Switch

Pseudocode                            Assembler

switch (selector) {              SWITCH:  cmp    selector, value1
    case value1: Statement1;              je     CASEvalue1
                 break;                   cmp    selector, value2
    case value2: Statement2;              je     CASEvalue2
                 break;                   jmp    DEFAULT
    default:     Default Statement;   CASEvalue1:
}                                         Instructions for Statement1
                                          jmp    ENDSWITCH
                                      CASEvalue2:
                                          Instructions for Statement2
                                          jmp    ENDSWITCH
                                      DEFAULT:
                                          Instructions for Default Statement
                                 ENDSWITCH:

 


Example:

switch (n) {                     SWITCH:  cmp         n, 1
  case 1: score = 95;                     je          CASE1
          break;                          cmp         n, 2
  case 2: score = 73;                     je          CASE2
          break;                          cmp         n, 5
  case 5: cout << Ax;                     je          CASE5
          break;                          jmp         DEFAULT
  default:score = 50;              CASE1: mov         score, 95
}                                         jmp         ENDSWITCH
                                   CASE2: mov         score, 73
                                          jmp         ENDSWITCH
                                   CASE2: call        WriteDec
                                          jmp         ENDSWITCH     
                                   DEFAULT: mov       score, 50
                                 ENDSWITCH:

And

 Pseudocode                              Assembler

 Condition1 AND Condition2                  cmp          opr1, opr2
                                            jCondition1  AND
                                            jmp          AND_FALSE
                                        AND:cmp          opr3, opr4
                                            jCondition2  AND_TRUE
                                            jmp          AND_FALSE
                                        AND_TRUE:
                                            Instructions when TRUE
                                        AND_FALSE:

 


Example:
 
 (eCX > 5 && AB != eCX)                         cmp    eCX, 5         
                                                jG     AND
                                                jmp    AND_FALSE
                                        AND:    cmp    AB, eCX
                                                jne    AND_TRUE
                                                jmp    AND_FALSE
                                        AND_TRUE:
                                               Instructions when TRUE
                                        AND_FALSE:

Or

Pseudocode                              Assembler

 Condition1 OR Condition2                  cmp             opr1, opr2
                                           jCondition1     OR_TRUE
                                   OR:     cmp             opr3, opr4

                                           jConditional2   OR_TRUE
                                           jmp             OR_FALSE
                                   OR_TRUE:
                                           Instructions when TRUE
                                   OR_FALSE:

 


Example:
 (eCX > 5 || AB != eCX)                         cmp    eCX, 5       
                                                jG     OR_TRUE
                                        OR:     cmp    AB, eCX
                                                jne    OR_TRUE
                                                jmp    OR_FALSE
                                        OR_TRUE:
                                              Instructions when TRUE
                                        OR_FALSE:

 

 


 

Common Errors

Relative Jump Out of Range - Relative jumps can branch forward 127 bytes and backward -128 bytes. The Assembler gives an error similar to:

 

**Error** for.asm(13) Relative jump out of range by 0018h bytes
The error is caused when the number of bytes between the conditional branch and the branch label exceeds this limit. This problem can occur for any conditional branch, an example implementing the do-while is:

 

do:                                ; do {
        :                                   :
        :                                   :
while:    Cmp    eAx, 5             : } while( Ax != 5 );
          Jne    do
endwhile:
This can be easily corrected by at least three methods:

 

  1. Reduce the number of instructions between the do: label and Jne conditional. This may not always be practical.
  2. Complement the logic of the conditional and use an unconditional branch to the distant target label, for example:
  3.  

      while:    Cmp    eAx, 5
                Je     endwhile
                Jmp    do
      endwhile:
  4. Keep the logic of the conditional but branch to an intermediate label that branches unconditionally to the distant target label, for example:
  5.  

      while:    Cmp    eAx, 5
                Jne    intermediate
                Jmp    endwhile
      intermediate:
                Jmp    do
      endwhile:

 


C++ Program Example 

// Simple 4 function calculator 
//
#include "iostream.h"

void main(void)
{
   int  opr1, opr2;
   char op;

   do {
       cin >> opr1;
       cin >> op;
       cin >> opr2;

       switch (op) {
          case '+' :  cout << opr1 + opr2;
                      break;
          case '-' :  cout << opr1 - opr2;
                      break;
          case '*' :  cout << opr1 * opr2;
                      break;
          case '/' :  cout << opr1 / opr2;
                      break;
       }
   } while (op != 'Q' && op != 'q'); 
}

Assembler Program Example 

; Simple 4 function calculator -  
;  Enter 12/3 as: 12
;                 /3  due to author's Input/Output


.Data    
        opr1    dd      ?                               ; int  opr1, opr2;
        opr2    dd      ?                               ; char op;
        op      db      ?

.Code   

 main   Proc    Far                     ; void main(void)
                     
  do1:                                  ;   do {
        Call    ReadDec                  ;       cin >> opr1;
        Mov     opr1, eAx
        Call    ReadChar                 ;       cin >> op;
        Mov     op, Al                  ;       
        Call    ReadDec                  ;       cin >> opr2;
        Mov     opr2, eAx 

     switch:                            ;       switch (op) {
        Cmp     op, '+'                 ;          case '+' :  cout << opr1 + opr2;
        Je      case1                   ;                      break;
        Cmp     op, '-'                 ;          case '-' :  cout << opr1 - opr2;
        Je      case2                   ;                      break;
        Cmp     op, '*'                 ;          case '*' :  cout << opr1 * opr2;
        Je      case3                   ;                      break;
        Cmp     op, '/'                 ;          case '/' :  cout << opr1 / opr2;
        Je      case4                   ;                      break;
        Jmp     endswitch
     case1:
        Mov     eAx, opr1
        Add     eAx, opr2
        Call    WriteDec
        Jmp     EndSwitch
     case2:
        Mov     eAx, opr1
        Sub     eAx, opr2
        Call    WriteDec
        Jmp     EndSwitch
     case3:
        Mov     eAx, opr1
        mul    opr2
        Call    WriteDec
        Jmp     EndSwitch
     case4:
        Mov     eAx, opr1
        Cwd
        div    opr2
        Call    WriteDec
     EndSwitch:                         ;         }
  while1:
        Cmp     op, 'Q'                 ;       } while (op != 'Q' && op != 'q');
        Jne     and1
        Jmp     endwhile1
     and1:
        Cmp     op, 'q'
        Jne     doJmp                   ; Jne do branch is too long, need
        Jmp     endwhile1               ; unconditional branch
     doJmp:
        Jmp     do1
  endwhile1:
       
 main   Endp                            ; }

        End     main

Document last modified: