Control Flow

Created

Decisions

if/then, switch

We want to jump unconditionally in order to:

  • Continue a loop
  • Complete a decision construct

This is the jmp construct.

  • This is unconditional, which is not directly useful for implementing decisions and loops, but is still useful and necessary for if-else logic.

Condition Codes are status bits updated by most ALU instructions to indicate the outcome of the instruction. Important condition code bits include:

  • CF: carry flag (unsigned operation overflowed)
  • ZF: zero flag (result was 0)
  • SF: sign flag (result was negative)
  • OF: overflow flag (signed operation overflowed)

These code bits reflect information about the outcome of the ALU operation. Stored in a special place maintained by the CPU.

These code bits can be used to make decisions in if-else logic or loops.

Comparing Values cmp instruction is essentailly the same as sub, except that it doesn't modify the "result" operand.

  • Used to compare integer values
  • AT&T syntax puts the operands in the opposite of the order you might expect
  • Intended to set condition codes.
cmpl %eax %ebx
  • This computes %ebx - %eax and sets conditions appropriately.

Testing Bits test instruction is essentially the same as and, but doesn't modify the "result" operand.

  • Good for testing if a certain bit is zero.
testl $0x80, %eax
  • sets ZF (zero flag) IFF bit 7 of %eax is 0.

Set Instructions setX instructions set a single byte to 0 or 1 depending on whether a condition code bit is set.

  • Useful to get the result of a comparison as a data value
  • Allows you to produce a boolean value depending on whether or not a particular condition code is set or not set.
setz %al
  • Sets %al (low byte of %rax) to 1 IFF ZF (zero flag) is set.

Conditional Jump We want to use the result of a comparison in order to influence a conditional jump instruction (used for implementing if/else logic and eventually-terminating loops).

Example instructions:

Signed comparisons:

  • je, jz when ZF meaning jump if equal
  • jl when SF ^ OF meaning jump if less
  • jle when (SF ^ OF) | ZF meaning jump if less than or equal
  • jg when ~(SF ^ OF) & ZF meaning jump if greater
  • jge when ~(SF ^ OF) meaning jump if greater than or equal

Unsigned comparisons

  • ja when ~CF & ~ZF meaning jump if above (unsigned)
  • jae when ~CF meaning jump if above or equal (unsigned)
  • jb when CF meaning jump if below (unsigned)
  • jbe when CF | ZF meaning jump if below or equal (unsigned)

If

Basic approach for implementing an if statement In C:

if (compare op1 and op2) {
	//conditionally-executed code
}
// rest of code...

In assembly

	cmp op2, op1
	jX .Lout 
	/* conditionally-executed code */

.Lout:
	/* rest of code */
  • The idea is that jX jumps to .Lout if the condition evaluates as false.

If Else

Basic approach for implementing an if/else statement In C:

if (compare op1 and op2) {
	// code if true
} else {
	//code if false
}
// rest of code

In assembly:

	cmp op2, op1
	jX .LelsePart
	/* code of true */
	jmp.Lout
.LelsePart:
	/* code of false */
.Lout:
	/* rest of code */
  • jX jumps to .LelsePart if the condition evaluates to false.

You should always write comments for every function in assembly.

Example:

cmpl $18, age
jl .LtooYoungToVote
movq $sCanVoteMsg, %rdi
jmp .LprintMsg

.LtooYoungToVote
	movq $sCannotVoteMsg, %rdi

.LprintMsg
  • cmpl $18, age compares the user input (age) with the value 18. It's the same as age >= 18?
  • jl means jump if less than, so if the age is less than 18, that's when we jump to the section that says that they are too young to vote.

Switch

switch statements: multiway branch based on an integer value.

  • One approach is to use an if/else or if/... if the range of tested integers is not dense.
  • Otherwise, if the range of tested integers is dense, you can use jump table.

A Jump Table is an array of code addresses. You look up an entry, and jump to that location. This is a always a constant time O(1) lookup.

  • This is a technique for the compiler to optimize if statements.

Example of a jump table:

	cmpl $1, %esi  
	jl .LDefaultCase  
	cmpl $12, %esi  
	jg .LDefaultCase  
	dec %esi  
	jmp *.LJumpTable(,%esi,8)

.L31DaysCase:

	code to handle months 1, 3, 5, etc.
	
	jmp .LSwitchDone 

.L30DaysCase:

	code to handle months 4, 6, 9, etc.
	
	jmp .LSwitchDone 

.LFebCase:

	code to handle month 2
	
	jmp .LSwitchDone 

.LDefaultCase:
	
	code to handle invalid month values

.LSwitchDone:
  • jmp *.LJumpTable(,%esi,8) jump table look up

And the actual jump table is an array of pointers, where the element values are code addresses specified using labels:

.LJumpTable:  
	.quad .L31DaysCase 
	.quad .LFebCase 
	.quad .L31DaysCase 
	.quad .L30DaysCase 
	.quad .L31DaysCase 
	.quad .L30DaysCase 
	.quad .L31DaysCase 
	.quad .L31DaysCase 
	.quad .L30DaysCase 
	.quad .L31DaysCase 
	.quad .L30DaysCase 
	.quad .L31DaysCase

Loops

for, while

While

To implement a loop (while) in assembly:

.Ltop:  
	cmp value, reg
	
	jX .Ldone 
	/* loop body */

         jmp .Ltop
         
 .Ldone:
	 code following loop...
  • Assumes that reg is a loop counter and jX is a conditional jump which, when taken, terminates the loop.
  • Professor's recommended way

Do While

A slightly more clever approach for this while loop is by by eliminating an unconditional jump from the loop body. Essentially a do while loop:

	jmp .LcheckCond

.Ltop:
	/* loop body */

.LcheckCond:  
	cmp value, reg

	jX .Ltop

	/* code following loop... */
  • Assume that reg is a loop counter and jX is a conditional jump which, when taken, continues the loop