CS 208 s22 — x86-64 Control Flow: Conditionals
Table of Contents
1 Review
What effect do these instructions
: leaq (%rdx,%rcx,4), %rax movq (%rdx,%rcx,4), %rbx leaq (%rdx), %rdi movq (%rdx), %rsi
have on register values give the initial state below?1
2 208 Reference Sheet
3 Jump Instructions
- x86 uses a dedicated register to store the address of the next instruction to execute
- called the instruction pointer or
%rip
- When an instruction executes,
%rip
is updated to be the address of the following instruction
- called the instruction pointer or
- Operations in C that jump to a different line of code (e.g., conditionals, loops, function calls) all involve changing which instruction will execute next—this is done by changing the value in
%rip
- class of
jump
instructions move program execution to specified instruction (figure 3.15, p. 206) - direct jumps encode the jump target in the instruction
- indirect jumps read the jump target from register or memory
- written with a
*
preceding the operand
- written with a
- conditional jumps (can only be direct) jump or continue the subsequent instruction based on some combination of condition codes
Instruction | (op) s, d |
test a, b |
cmp a, b |
||
---|---|---|---|---|---|
jmp |
Unconditional | ||||
je |
sete |
"Equal" | d (op) s == 0 |
b & a == 0 |
b == a |
jne |
setne |
"Not equal" | d (op) s != 0 |
b & a != 0 |
b != a |
js |
sets |
"Sign" (negative) | d (op) s < 0 |
b & a < 0 |
b - a < 0 |
jns |
setns |
(non-negative) | d (op) s >= 0 |
b & a >= 0 |
b - a >= 0 |
jg |
setg |
"Greater" | d (op) s > 0 |
b & a > 0 |
b > a |
jge |
setge |
"Greater or equal" | d (op) s >= 0 |
b & a >= 0 |
b >= a |
jl |
setl |
"Less" | d (op) s < 0 |
b & a < 0 |
b < a |
jle |
setle |
"Less or equal" | d (op) s <= 0 |
b & a <= 0 |
b <= a |
ja |
seta |
"Above" (unsigned >) | d (op) s > 0U |
b & a > 0U |
b - a > 0U |
jb |
setb |
"Below" (unsigned <) | d (op) s < 0U |
b & a < 0U |
b - a < 0U |
3.1 Implementing Conditional Branches with Conditional Control
if (<text-expr>) <then-statement> else <else-statement>
becomes
t = <test-expr>; if (!t) goto false; <then-statement> goto done; false: <else-statement> done:
3.1.1 Example
long absdiff(long x, long y) { long result; if (x > y) result = x - y; else result = y - x; return result; }
Register | Use |
---|---|
%rdi |
1st argument (x ) |
%rsi |
2nd argument (y ) |
%rax |
return value |
absdiff: cmpq %rsi, %rdi // perform x - y jle .L4 // if condition codes indicate x <= y, jump to L4 // x > y: movq %rdi, %rax subq %rsi, %rax ret .L4: // x <= y: movq %rsi, %rax subq %rdi, %rax ret
3.2 (OPTIONAL) Implementing Conditional Branches with Conditional Moves
- Reading: CSPP section 3.6.6
- class of
cmov
instructions copy source operand to destination register when the condition holds- same conditions as
set
andjump
instructions
- same conditions as
- can be more efficient than conditional jumps because the sequence of intructions is predictable
- memory may or may not be moved, but the subsequent instruction is executed regardless
- processors pipeline instructions, meaning they process them in a series of stages (fetching instruction from memory, determining instruction type, reading from memory, performing arithmetic operation, writing to memory, updating program counter)
- significant performance benefits from overlapping different stages of sequential instructions
- pipelining in the presence of conditional jumps requires sophisticated branch prediction (modern processors aim for 90% accuracy)
- turn on optimization for previous exercise (
-O1
compiler flag) to see an example
4 Conditional Exercise
Translate this C code to assembly2
long wacky(long x, long y) { long result; if (x + y > 7) { result = x; } else { result = y + 2; } return result; }
4.1 Jump Instruction Encodings
If we compile wacky
and disassemble it, we can see how jump instructions are encoded into machine code3:
0000000000400497 <wacky>: 400497: 48 8d 04 37 lea (%rdi,%rsi,1),%rax 40049b: 48 83 f8 07 cmp $0x7,%rax 40049f: 7f 05 jg 4004a6 <wacky+0xf> 4004a1: 48 8d 46 02 lea 0x2(%rsi),%rax 4004a5: c3 retq 4004a6: 48 89 f8 mov %rdi,%rax 4004a9: c3 retq
- jump target encoded compactly with instruction pointer relative representation
- specify offset to the address of the immediately following instruction
7f
is the encoding for thejg
instruction05
is the jump target, meaning it will add0x5
to%rip
(the instruction pointer) if it jumps- when we execute the
jg
instruction,%rip
is set to the address of the next instruction,0x4004a1
. Adding0x5
to this will result in executing themov
instruction at0x4004a6
instead. objdump
, the disassembler I used to produce the above example, computes this for us and displays0x4004a6
as the jump target even though in the machine code the target is encoded as0x5
5 Condition Codes
- condition codes are the basis for control flow within a program (i.e., determining which instruction gets executed next)
- special
%rip
register stores instruction pointer
- special
- most useful codes:
CF
: carry flag. Set when an operation generated a carry out of the most significant bit. Used to detect unsigned overflowZF
: zero flag. Set when an operation yields 0SF
: sign flag. Set when an operation yields a negative valueOF
: overflow flag. Set when an operation causes a two's complement overflow, negative or positive
- all the standard arithmetic instructions set these flags except for
leaq
cmp
andtest
instructions set condition codescmp
subtracts first operand from secondtest
ands operands (usually the same quantity is both operands, check if its zero, positive, negative)
5.1 Accessing the Condition Codes
- class of
set
instructions to set a single byte to 1 or 0 based on one or more condition codes (figure 3.14, p. 203)- in the case where
cmp b, a
was executed - when \(a=b\), then \(a-b=0\), so
ZF
will be set - when \(a < b\), then \(a - b < 0\) (
SF
set) or \(a - b\) overflows so the result is positive andOF
is set- but both
SF
andOF
set would indicate \(a\) is positive and \(b\) is negative such that \(a-b\) would overflow to a negative value - hence, less than is detected when
SF ^ OF
- but both
- for unsigned \(a < b\), \(a - b\) would cause a carry out of the most significant bit, setting
CF
- in the case where
5.2 Example
5.2.1 Translate conditional C code to assembly
long val_or_default(long *x, long y) { if (x == NULL) { return y; } return *x; }
Register | Use |
---|---|
%rdi |
1st argument (x ) |
%rsi |
2nd argument (y ) |
%rax |
return value |
val_or_default: testq %rdi, %rdi je .L4 movq (%rdi), %rax ret .L4: movq %rsi, %rax ret
6 movz
and movs
- when moving data from a smaller source to a larger destination, can specify zero extension or sign extension
- destination must be a register
movzSD
/movsSD
S
is the size of the source (b
orw
)D
is the size of the destination (w
,l
, orq
)
7 Which condition codes indicate \(a > b\)?
- not less than and not equal
~(SF ^ OF)
and~ZF
~(SF ^ OF) & ~ZF
8 Practice
CSPP practice problems 3.16 (p. 212) and 3.18 (p. 213)
Footnotes:
2
wacky: leaq (%rdi,%rsi), %rax cmpq $7, %rax jg .L3 leaq 2(%rsi), %rax ret .L3: movq %rdi, %rax ret
3
Perform this disassembly via an option on godbolt.org
or, by putting the code for wacky
and an empty main
in wacky.c
and running these commands:
gcc -Og -no-pie -o wacky wacky.c objdump -d wacky
objdump
will print out a bunch of boilerplate assembly that's part of any program, so you'll need to locate the definition of wacky
within it.