Lecture 15 - Control Flow I

Published

March 13, 2026

Goals

  • Learn how x86 handles data movement
  • Start thinking about control flow
  • Learn about the branch instruction

I want to start by wrapping up some of the details from last time

x86

We looked at load and store on the ARM, what do they look like for x86?

it is all handled by the MOV command


mov eax, [ebx]

Meaning: eax ← Mem[ebx] (load base)
mov eax, [imm]

Meaning: eax ← Mem[imm] (load immediate)

mov [ebx], eax

Meaning: Mem[ebx] ← eax (store base)

mov ebx, [esi + 2*ecx]

Meaning: ebx ← Mem[esi + 2*ecx] (load base + scaled register)

There are, as you may imagine, some other variants, but these cover most of the important bases

Flow of execution

Now that we have a little more of an idea how memory and the processor work together, lets get a little more detailed about the fetch execute cycle for ARM32

Lets talk about a simple little assembly program


mov r0, #180
mov r1, #42
add r2, r0, r1

xor r0, r0, r0
str r2, [r0]

As you will recall, I described a special register called the program counter that stored the address of the next instruction to be executed.

For our ARM processors, the PC hangs out with the rest of the registers in the register file as r15. The implication of this is that we can read the value and even change it (though it is usually not a good idea to arbitrarily meddle with it).

if I tell you that the first instruction here starts at address 96, what can we say about the instructions

before any instructions are executed


r0 ?
r1 ?
r2 ?
...
r15 96

We grab the instruction pointed to by the PC, and execute it. So, r0 now holds a 180. Meanwhile, we increment the PC to… 100


mov r0, #180

r0 180
r1 ?
r2 ?
...
r15 100

Why 100?

  • we know that each instruction is 32 bits
  • we know that ARM uses byte-level addressing
  • so, when we update r15, we need to increment it by… 4

mov r1, #42

r0 180
r1 42
r2 ?
...
r15 104

add r2, r0, r1

r0 180
r1 42
r2 222
...
r15 108

xor r0, r0, r0

r0 0
r1 42
r2 222
...
r15 112

What is going on with xor r0, r0, r0?

What do we get if we xor a number with itself? zero

So this is quick way to zero out a register


xor r0, r0, r0

r0 0
r1 42
r2 222
...
r15 116

Control flow

So far, so good. However, this won’t lead to very interesting programs. For interesting and complex programs we want something like our conditional statements, loops and function calls.

In other words we need a way to change the control flow and break away from the rigid updating of PC ← PC + 4

Let’s consider the simplest of our control statements – the if statement


if (condition){
    //do_conditional_thing
}

//do_next_thing

If the condition is true, then we do the conditional thing and then we do the next thing. If the condition is false, then we just do the next thing.

Now let’s imagine this as a block of assembly instructions. We are advancing through the instructions, with the PC remorselessly incrementing by 4 for every instruction. We get to right before this conditional statement. Let’s imagine, for a moment that the condition is just a value – 0 or 1.

If the condition is a 1, then we want to just keep trucking along and advance to the next instruction, which will be our “conditional thing”

If the condition is a 0, then we want to jump over the conditional instructions and advance to the next thing. So, we need some way to keep the PC from getting its normal +4 and replacing the value with the address of the next.

Note that this new way of thinking about it is slightly counter intuitive. We usually think about it the opposite way – if this condition is true then do this thing. We are turning this on its head and inverting the condition to say if the inverted condition is true, then skip over this stuff.

Mechanical level

vocabulary

Skills