8. Branch Instructions
Branch instructions are what make programs “intelligent” - they allow your code to make decisions, repeat actions, and respond to different conditions. This is where we implement if statements, loops, and all conditional logic.
What are Branch Instructions?
Branch instructions change the flow of program execution based on conditions. They work by:
- Checking flags set by previous operations
- Deciding whether to jump to a different location
- Modifying RIP (Instruction Pointer) to change what executes next
Types of Jumps
1. Unconditional Jump (JMP)
Always jumps to the specified label.
1
2
3
4
jmp my_label ; Always jump to my_label
; Code here won't execute
my_label:
; Execution continues here
2. Conditional Jumps
Jump only if specific flag conditions are met. These are the workhorses of decision-making.
Conditional Jump Categories
A. Equality Comparisons (based on ZF)
| Instruction | Condition | Description |
|---|---|---|
| JE / JZ | ZF = 1 | Jump if Equal / Jump if Zero |
| JNE / JNZ | ZF = 0 | Jump if Not Equal / Jump if Not Zero |
1
2
3
4
5
6
7
8
9
mov rax, 10
mov rbx, 10
cmp rax, rbx ; Sets ZF=1 (they are equal)
je they_are_equal ; This jump WILL be taken
mov rax, 10
mov rbx, 20
cmp rax, rbx ; Sets ZF=0 (they are not equal)
je they_are_equal ; This jump will NOT be taken
B. Unsigned Comparisons (based on CF)
Used when comparing unsigned numbers.
| Instruction | Condition | Description |
|---|---|---|
| JB / JNAE | CF = 1 | Jump if Below / Jump if Not Above or Equal |
| JAE / JNB | CF = 0 | Jump if Above or Equal / Jump if Not Below |
| JA / JNBE | CF=0 and ZF=0 | Jump if Above / Jump if Not Below or Equal |
| JBE / JNA | CF=1 or ZF=1 | Jump if Below or Equal / Jump if Not Above |
1
2
3
4
5
6
7
8
9
mov al, 200 ; Unsigned: 200
mov bl, 100 ; Unsigned: 100
cmp al, bl
ja above ; Jump because 200 > 100 (unsigned)
mov al, 50 ; Unsigned: 50
mov bl, 100 ; Unsigned: 100
cmp al, bl
jb below ; Jump because 50 < 100 (unsigned)
C. Signed Comparisons (based on SF and OF)
Used when comparing signed numbers.
| Instruction | Condition | Description |
|---|---|---|
| JL / JNGE | SF ≠ OF | Jump if Less / Jump if Not Greater or Equal |
| JGE / JNL | SF = OF | Jump if Greater or Equal / Jump if Not Less |
| JG / JNLE | ZF=0 and SF=OF | Jump if Greater / Jump if Not Less or Equal |
| JLE / JNG | ZF=1 or SF≠OF | Jump if Less or Equal / Jump if Not Greater |
1
2
3
4
5
6
7
8
9
mov al, -10 ; Signed: -10
mov bl, 5 ; Signed: +5
cmp al, bl
jl less ; Jump because -10 < 5 (signed)
mov al, -5 ; Signed: -5
mov bl, -10 ; Signed: -10
cmp al, bl
jg greater ; Jump because -5 > -10 (signed)
Let’s see some practical examples of Branch Instructions.
Example 1: Simple If-Else
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
section .text
global _start
_start:
mov rax, 15
mov rbx, 20
cmp rax, rbx
jg greater
jl less
; If we get here, they're equal
equal:
; rax == rbx
jmp end
greater:
; rax > rbx
jmp end
less:
; rax < rbx
end:
mov rax, 60
mov rdi, 0
syscall
Example 2: Loop with Counter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
section .text
global _start
_start:
mov rcx, 5 ; Loop counter
mov rax, 0 ; Sum
loop_start:
add rax, rcx ; Add counter to sum
dec rcx ; Decrement counter
jnz loop_start ; Jump if RCX != 0
; Now RAX = 5+4+3+2+1 = 15
mov rax, 60
mov rdi, 0
syscall
Common Patterns and Idioms
Infinite Loop:
1
2
3
infinite_loop:
; Do something
jmp infinite_loop
Skip Code Block:
1
2
3
4
cmp rax, 0
jz skip_block
; Code to skip if RAX == 0
skip_block:
Keep this in mind.
JG is used for signed comparisons. For unsigned comparisons, you would use JA (Jump if Above).
Example the following code has a problem
1
2
3
4
5
mov rax, -1 ; Signed: -1
mov rbx, 255 ; Unsigned: 255
cmp rax, rbx
jg signed_compare ; Uses signed comparison!
; -1 > 255? No! But 255 > -1? Yes for unsigned!
- Signed comparison treats values as if they’re part of a signed number system, which means it accounts for positive and negative numbers.
- Unsigned comparison treats all values as positive, and doesn’t account for sign at all.
rax contains -1, which, in two’s complement representation (the most common way to represent negative numbers in a computer), is represented as 0xFFFFFFFFFFFFFFFF in 64-bit. And rbx contains 255, which is simply 0xFF in 64-bit.
The cmp instruction performs a signed comparison. So, -1 (in signed comparison) is considered “larger” than 255 in this case, because -1 is represented as the largest 64-bit signed value (0xFFFFFFFFFFFFFFFF), and 255 is much smaller in signed terms. However, if you were to perform unsigned comparison, the situation would be reversed, and 255 would be considered “larger” than -1, since unsigned comparison treats -1 as a very large positive number (specifically, 0xFFFFFFFFFFFFFFFF).
To perform an unsigned comparison, you need to use the ja (jump if above) or jae (jump if above or equal) instructions instead of jg. The jg instruction is for signed comparisons.
1
2
; jg signed_compare
ja unsigned_compare ; Use unsigned comparison!
To clear this again lemme clarify again. When you compare -1 (which is 0xFFFFFFFFFFFFFFFF in two’s complement) and 255 (0xFF), we need to distinguish between signed and unsigned comparisons:
In signed comparison:
raxcontains-1, which is a negative number.rbxcontains255, which is positive.- So, in signed comparison,
-1is less than255because negative numbers are always smaller than positive numbers.
In unsigned comparison:
raxcontains0xFFFFFFFFFFFFFFFF(which is very large in unsigned terms).rbxcontains255(0xFF), which is much smaller in unsigned terms.- So, in unsigned comparison,
-1(which is treated as the maximum unsigned value) is greater than255.
jg (jump if greater) is a signed comparison that checks if the value in rax is greater than rbx assuming signed numbers.
Since we are dealing with a signed number (rax = -1) and an unsigned number (rbx = 255), and you want to check if -1 is greater than 255 in unsigned comparison, we should use ja (jump if above) correctly — because in unsigned comparison, -1 is treated as a very large number (i.e., 0xFFFFFFFFFFFFFFFF), which is indeed greater than 255.
Use the following code in SASM to get better picture while debugging -
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
%include "io64.inc"
section .text
global CMAIN
CMAIN:
mov rbp, rsp ; for correct debugging
mov rax, -1 ; Signed: -1
mov rbx, 255 ; Unsigned: 255
cmp rax, rbx
; jg signed_compare ; Uses signed comparison! <-- This is incorrect for unsigned comparison.
ja unsigned_compare ; Correct: Use unsigned comparison (rax > rbx in unsigned terms)
mov rax, 60
mov rdi, 0x1
syscall
unsigned_compare: ; New label for unsigned comparison
jmp end
end:
mov rax, 60
syscall
You can checkout this page