Chapter 6Conditional Processing |
Modified: |
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.
6.2.1 CPU Flags
ZF Zero flag is set when the result of an operation equals zero.
CF Carry flag is set when an instruction generates a result that is too large (or too small) for the destination operand, an invalid unsigned number.
SF Sign flag is set if the destination operand is negative, and it is clear if the destination operand is positive.
OF Overflow flag is set when an instruction generates an invalid signed result (bit 7 carry is XORed with bit 6 Carry).
PF Parity flag is set when an instruction generates an even number of 1 bits in the low byte of the destination operand.
AF Auxiliary Carry flag is set when an operation produces a carry out from bit 3 to bit 4
6.2.2 Boolean and Comparison Instructions
Logical instructions are based upon the definition of And, OR, XOR, and Not logic operations.Bit-wise InstructionsThe logical operations are often used when controlling hardware, such as a printer interface as given in the example below.
Definition of And, Xor, Or, Not And Or Xor Not A B|A AND B A B|A AND B F F| F 0 0| 0 F T| F 0 1| 0 T F| F 1 0| 0 T T| T 1 1| 1 A B| A OR B A B|A OR B F F| F 0 0| 0 F T| T 0 1| 1 T F| T 1 0| 1 T T| T 1 1| 1 A B A XOR B A B|A XOR B F F| F 0 0| 0 F T| T 0 1| 1 T F| T 1 0| 1 T T| F 1 1| 0 A | Not A 0 | 1 1 | 0
Useful ResultsAnd Or Xor Set bit to 0 A B|A AND B 0 0| 0 0 1| 0Copy bit B A B|A AND B 1 0| 0 1 1| 1 Set bit to 1 A B|A OR B 1 0| 1 1 1| 1Copy bit B A B|A OR B 0 0| 0 0 1| 1 Xor is its own inverse 10101 XOR 11100 01001 XOR 11100 10101
The And, Or, Xor, Test, and Not instructions apply the corresponding logical definition to each bit of the operand.Note that Test is identical to And except that it only sets the flags but does not produce a result.
Bit-wise And, Or, Xor, Not And Test Or Xor Not Mov Ah, 11110000B And Ah, 00110011B Ah = 00110000 ZF = 0 SF = 0 Mov Ah, 11110000B Test Ah, 00110011B Ah = 11110000 ZF = 0 SF = 0 Mov Ah, 11110000B Or Ah, 00110011B Ah = 11110011 ZF = 0 SF = 1 Mov Ah, 11110000B Xor Ah, 00110011B Ah = 11000011 ZF = 0 SF = 1 Mov Ah, 11110000B Not Ah Ah = 00001111 ZF = 0 SF = 0
Examples of And, Test, and Or Upper to lowercase conversion Mov Bh, 01000001B ; = 'A' = 41h Or Bh, 00100000B ; Upper to lowercase Bh = 01100001 = 'a' Lower to uppercase conversion Mov Bh, 01100001B ; = 'a' = 61h And Bh, 11011111B ; Lower to uppercase Bh = 01000001 = 'A' Check if printer has paper Mov Dx, 379h ;Printer Status address In Al, Dx ;Input printer status And Al, 00100000B ;Bit 5 == 0 when paper If bit 5 == 0 then AL = 00000000 ZF = 1 See page 460 of text for printer status Wait for printer to be ready Mov Dx, 379h ;Printer Status repeat: ;repeat In Al, Dx ; until !Busy&&Paper&&Online And Al, 10110000B ;Bits 7 5 4 until: ; Busy=1 Paper=0 Online=1 Cmp Al, 10010000B Jnz repeat endrepeat:
Question 1
What are Ah, ZF and SF?
Bit-wise And, Or, Xor, Not And Test Or Xor Not Mov Ah, 11110100B And Ah, 01110011B Ah = ZF = SF = Mov Ah, 11110100B Test Ah, 00110111B Ah = ZF = SF = Mov Ah, 11011000B Or Ah, 00010011B Ah = ZF = SF = Mov Ah, 11110000B Xor Ah, 01111011B Ah = ZF = SF = Mov Ah, 10000001B Not Ah Ah = ZF = SF =
6.2.7 CMP Instruction
CMP performs a SUB operation but only affecting the flags.
CMP Destination, Source
CMP results ZF CF Destination < Source 0 1 Destination > Source 0 0 Destination = Source 1 0 The add and subtract operation can operate on signed or unsigned numbers, either 8, 16 or 32-bit operands. The result is the same size as the operands so it is possible that incorrect results are produced when the result is too large or small. Remember that subtraction is performed by addition of a negative number.
- Unsigned - Addition and subtraction of unsigned numbers is invalid whenever there is a carry out, CF = 1 (CF is carry flag).
The result is valid as an unsigned number when CF=0.
The carry flag is the carry out from the leftmost bit for addition.
For subtraction the carry out is inverted, a natural carry out of 1 is inverted by the CPU to 0 and vice versa.
- Signed - Addition and subtraction of of signed numbers is invalid whenever there is an overflow, OF = 1 (OF is overflow flag).
The result is valid as a signed number when OF=0.
The OF = 0 when the carry into the leftmost bit equals the carry out of the leftmost bit, otherwise OF=1.
Cmp
Unsigned 11111111 Signed Carry into and out of leftmost 8 bits 110 000000012 110 bit equal, OF=0. -8 bits -110 = +111111112 -110 8 bits 010 1000000002 0 Valid unsigned, CF=0 since inverted on subtraction. CF = 0 ZF = 1 Mov Ah, 1 OF = 0 SF = 0 Valid signed, OF=0. Cmp Ah, 1 Ah = 00000001
Unsigned 11111110 Signed Carry into and out of leftmost 8 bits 210 000000102 210 bit equal, OF=0. -8 bits -110 = +111111112 -110 8 bits 110 1000000012 = 110 Valid unsigned 128, CF=0, inverted. CF = 0 ZF = 0 Invalid signed -128, OF=1. Mov Ah, 2 OF = 0 SF = 0 Cmp Ah, 1 Ah = 00000010
Unsigned 00000000 Signed Carry in 0, carry out of leftmost 8 bits 110 000000012 110 bit 0, OF=0. -8 bits -210 = +111111102 -210 8 bits 12710 0111111112 = -110 Invalid unsigned CF=1, inverted. CF = 1 ZF = 0 Valid signed OF=1. Mov Ah, 1 OF = 0 SF = 1 Cmp Ah, 2 Ah = 00000001
Question 2
What are Ah, CF, OF, SF and ZF?
CF = ZF = Mov Ah, 2 OF = SF = Cmp Ah, 3 Ah =
CF = ZF = Mov Ah, 3 OF = SF = Cmp Ah, 2 Ah =
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.
![]() |
Mov eAx, 0 Call WriteDec Inc eAx Mov eDx, OFFSET Done Call WriteStrng Output: 0 Done |
Mov eAx, 0 A: Call WriteDec Inc eAx Jmp A Mov eDx, OFFSET Done Call WriteStrng Output: 0 1 2 ... |
Mov eAx, 0 A: Call WriteDec Inc eAx Cmp eAx, 10 JL A Mov eDx, OFFSET Done Call WriteStrng Output: 0 1 2 ... 8 9 Done |
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 eAx= ...0, 1, 2, ..., FFFFFFFF, 0, 1, 2, ...
A: Call WriteDec Inc eAx Jmp A |
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:
- fetch instruction Jmp A at IP value, offset 0006,
- update IP to next instruction, offset 0009
- execute Jmp A by setting IP to 0002, the offset of the label 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 |
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:
eAx = 0; A: cout << eAx;
eAx++;
cout << "Done"; |
Mov eAx, 0 A: Call WriteDec Inc eAx
Mov eDx, OFFSET Done Call WriteString |
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.
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.
| 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 |
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 eCx, 4 is executed.
A: Call WriteDec Inc eAx Cmp eAx, 10 JL A Mov eCx, 4 |
|
|||||||||||||||||||||||||||||
|
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.
10 00000003 8E D8 Mov Ds, Ax 11 12 00000005 74 09 Je A 13 14 00000007 EB 00000010 Jmp A 15 16 0000000A C7 06 0000r 000A Mov X, 10 17 18 00000010 C7 06 0000r 000B A: Mov X, 11 19 20 00000016 C7 06 0000r 000C Mov X, 12 21 22 0000001C 74 F2 Je A 23 24 0000001E B4 4C Mov Ah, 4ch |
The problem that occasionally 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 any number of 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.
| 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 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:
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.
- Sequential - The next sequential instruction is executed
- Iteration - A sequence of instructions are repeatedly executed for a specified number of iterations. Example: FOR, WHILE
- Conditional - An instruction is conditionally executed based upon a conditional expression being true. Example: IF
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 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 |
Question 3
Translate the following into structured assembly:
if( al == 5)
bl = 'O'
else
bl = 'X'
Question 4
Translate the following into structured assembly:
eAx = 0
while ( eAx <= 5) {
eAx = eAx + 1
print( eAx )
}
Question 5
Translate the following into structured assembly:
for ( eAx = 0; eAx < 5; eAx++) {
print( eAx )
}
Question 6
Translate the following into structured assembly:
eAx = 0
repeat {
eAx++
print( eAx )
} until( eAx == 5 )
Question 7
Translate the following into structured assembly:
eAx = 0
do {
eAx++
print( eAx )
} while ( eAx < 5 )
Question 8
Translate the following into structured assembly:
eAx = 0
switch( eAx) {
case 0 : eAx++
break
case 1 : eAx--
break
default : eAx = 0
}
Example - Linear Search of an array
Following searches an array for given value. Returns:
-1 if not found
array index if found.
|
int array[] = {1,-20,35,-12,66,4};
void main() {
int Search( int eAx ) { |
INCLUDE Irvine32.inc .data Found BYTE "Found", 0 NotFound BYTE "Not Found", 0 array DWORD 1,-20,35,-12,66,4 .code
Main Proc
Mov eAx, -12
Call Search
@@if: Cmp eAx, -1
Je @@then
Jmp @@else
@@then:
Mov eDx, OFFSET NotFound
Call WriteString
Jmp @@endif
@@else:
Mov eDx, OFFSET Found
Call WriteString
@@endif:
Exit
Main Endp
Search Proc
Mov eCx, 6
Mov eSi, 0
@do:
@if: Cmp array[ eSi ], eAx
Je @then
Jmp @endif
@then:
Mov eAx, eCx
Ret
@endif:
Add eSi, 4
@while: Loop @do
Mov eAx, -1
Ret
Search Endp
End Main
|
AND and OR logical operators create compound expressions.
Short-circuiting means that logical operands are evaluated left-to-right until the logical result can be determined. For example:
i = -1; if( i >= 0 && x[ i ] < 5)
print( x[ i ] );mov eSi, -1
@if: cmp eSi, 0
jge @and
jmp @endif
@and: cmp x[ eSi ], 5
jl @then
jmp @endif
@then: mov eAx, x[ eSi ]
call WriteDec
@endif:because i >= 0 is false, i >= 0 && x[ i ] < 5 can not be true, x[ i ] < 5 is not evaluated.
i >= 0 serves as a guard to prevent indexing the array x with a negative index.
Question 9
Translate the following into structured assembly:
if( eAx >= 0 && eAx < 10) print(eAx);
Below, because i >= 0 is true, i >= 0 || x[ i ] < 5 will be true, x[ i ] < 5 is not evaluated.
i = 1; if( i >= 0 || x[i] < 5)
print( i );mov eSi, -1
@if: cmp eSi, 0
jge @then
@or: cmp x[ eSi ], 5
jl @then
jmp @endif
@then: mov eAx, x[ eSi ]
call WriteDec
@endif:
Question 10
Translate the following into structured assembly:
if( eAx >= 0 || eAx < -10) print(eAx);
Example - Four function calculator
User enters: 5
+ 4Output: 9
6.7 Decision Directives
We have constructed structured programs by creating if, while, and repeat statements.
The assembler has directives that automatically generate the code necessary to implement those statements.
Using directives can make your program more readable and source code that you write, smaller.
Because directives generate additional code that becomes part of your program, debugging traces are more difficult to follow.
.IF
Example - column 2 is generated by the assembler from the .IF directive in column 1.
.IF eax > ebx
mov edx,1
.ELSE
mov edx,2
.ENDIF.IF eax > ebx
cmp eax,ebx
jbe @C0001
mov edx,1
.ELSE
jmp @C0003
@C0001 mov edx,2
@C0003
.ENDIFif( eax > ebx)
edx = 1;
else
edx = 2;Example
.IF eax > ebx && ebx < 10
mov edx,1
.ELSE
mov edx,2
.ENDIFif( eax > ebx && ebx < 10)
edx = 1;
else
edx = 2;
Question 11
Translate the following into structured assembly using .IF:
if( eAx >= 0 ) print(eAx);
else
eAx--;
.WHILE
Example
mov eAx, 10
.WHILE eax > 0
Call WriteInt
Call CrLf
dec eAx
.ENDWeAx = 10;
while( eax > 0) {
print( eAx );
eAx--;
}
Example
mov eAx, 10
.WHILE eax > 0 && eax <=10
Call WriteInt
Call CrLf
dec eAx
.ENDWeAx = 10;
while( eax > 0 && eax <= 10) {
print( eAx );
eAx--;
}
Question 12
Translate the following into structured assembly using .WHILE:
while( eAx >= 0 && eAx < 10) { eAx--;
print( eAx );
}
.REPEAT
Example
mov eAx, 10
.REPEAT
Call WriteInt
Call CrLf
dec eAx
.UNTIL eAx == 0eAx = 10;
do {
print( eAx );
eAx--;
} while( eax != 0)
Question 13
Translate the following into structured assembly using .REPEAT:
do { eAx--;
print( eAx );
} while( eAx >= 0 && eAx < 10)
Example - Linear Search of an array
Search function searches an array for given value. Returns:
-1 if not found
array index if found.
|
int array[] = {1,-20,35,-12,66,4};
void main() {
int Search( int eAx ) { |
INCLUDE Irvine32.inc
.data
Found BYTE "Found", 0
NotFound BYTE "Not Found", 0
array DWORD 1,-20,35,-12,66,4
.code
Main Proc
Mov eAx, -12
Call Search
.IF eAx == -1
Mov eDx, OFFSET NotFound
Call WriteString
.ELSE
Mov eDx, OFFSET Found
Call WriteString
.ENDIF
Exit
Main Endp
Search Proc
Mov eCx, 6
Mov eSi, 0
.REPEAT
.IF array[ eSi ] == eAx
Mov eAx, eCx
Ret
.ENDIF
Add eSi, 4
Dec eCx
.UNTIL eCx == 0
Mov eAx, -1
Ret
Search Endp
End Main
|