x86 Assembly/Control Flow
Almost all programming languages have the ability to change the order in which statements are evaluated, and assembly is no exception. The instruction pointer (EIP) register contains the address of the next instruction to be executed. To change the flow of control, the programmer must be able to modify the value of EIP. This is where control flow functions come in.
mov eip, label ; wrong
jmp label ; right
Comparison Instructions
[edit | edit source]test reference, accumulator | GAS Syntax |
test accumulator, reference | Intel Syntax |
Performs a bit-wise logical and
on accumulator
and reference
the result of which we will refer to as commonBits
and sets the ZF
(zero), SF
(sign) and PF
(parity) flags based on commonBits
. CommonBits
is then discarded.
Operands
reference
- Register
- Immediate
accumulator
- Register (where
AL/AX/EAX
can be encoded specially ifreference
is an immediate value) - Memory
Modified flags
SF
≔ MostSignificantBit(commonBits
)ZF
≔ (commonBits
= 0), so a setZF
means,accumulator
andreference
do not have any set bits in commonPF
≔ BitWiseXorNor(commonBits
[Max-1:0]), soPF
is set if and only ifcommonBits
[Max-1:0] has an even number of 1 bitsCF
≔ 0OF
≔ 0AF
is undefined
Application
- passing the same register twice:
test rax, rax
SF
becomes the sign ofrax
, which is a simple test for non-negativityZF
is set ifrax
is zeroPF
is set ifrax
has an even number of set bits
cmp subtrahend, minuend | GAS Syntax |
cmp minuend, subtrahend | Intel Syntax |
Performs a comparison operation between minuend
and subtrahend
. The comparison is performed by a (signed) subtraction of subtrahend
from minuend
, the results of which can be called difference
. Difference
is then discarded. If subtrahend
is an immediate value it will be sign extended to the length of minuend
. The EFLAGS
register is set in the same manner as a sub
instruction.
Note that the GAS/AT&T syntax can be rather confusing, as for example cmp $0, %rax
followed by jl branch
will branch if %rax < 0
(and not the opposite as might be expected from the order of the operands).
Operands
minuend
AL/AX/EAX
(only ifsubtrahend
is immediate)- Register
- Memory
subtrahend
- Register
- Immediate
- Memory
Modified flags
SF
≔ MostSignificantBit(difference
), so an unsetSF
means thedifference
is non-negative (minuend
≥subtrahend
[NB: signed comparison])ZF
≔ (difference
= 0)PF
≔ BitWiseXorNor(difference
[Max-1:0])CF
,OF
andAF
Jump Instructions
[edit | edit source]The jump instructions allow the programmer to (indirectly) set the value of the EIP register. The location passed as the argument is usually a label. The first instruction executed after the jump is the instruction immediately following the label. All of the jump instructions, with the exception of jmp
, are conditional jumps, meaning that program flow is diverted only if a condition is true. These instructions are often used after a comparison instruction (see above), but since many other instructions set flags, this order is not required.
See chapter “X86 architecture”, § “EFLAGS register” for more information about the flags and their meaning.
Unconditional Jumps
[edit | edit source]jmp loc
Loads EIP
with the specified address (i.e. the next instruction executed will be the one specified by jmp
).
Jump if Equal
[edit | edit source]je loc
ZF = 1
Loads EIP
with the specified address, if operands of previous cmp
instruction are equal. je
is identical to jz
.
For example:
mov ecx, $5
mov edx, $5
cmp ecx, edx
je equal
; if it did not jump to the label equal,
; then this means ecx and edx are not equal.
equal:
; if it jumped here, then this means ecx and edx are equal
Jump if Not Equal
[edit | edit source]jne loc
ZF = 0
Loads EIP
with the specified address, if operands of previous cmp
instruction are not equal. jne
is identical to jnz
Jump if Greater
[edit | edit source]jg loc
SF = OF and ZF = 0
Loads EIP
with the specified address, if the minuend
of the previous cmp
instruction is greater than the second (performs signed comparison).
Jump if Greater or Equal
[edit | edit source]jge loc
SF = OF or ZF = 1
Loads EIP
with the specified address, if the minuend
of the of previous cmp
instruction is greater than or equal to the subtrahend
(performs signed comparison).
Jump if Above (unsigned comparison)
[edit | edit source]ja loc
CF = 0 and ZF = 0
Loads EIP
with the specified address, if the minuend
of the previous cmp
instruction is greater than the subtrahend
.
ja
is the same as jg
, except that it performs an unsigned comparison.
That means, the following piece of code always jumps (unless rbx
is -1
, too), because negative one is represented as all bits set in the two's complement.
mov rax, -1 // rax := -1
cmp rax, rbx
ja loc
Interpreting all bits set (without treating any bit as the sign) has the value 2ⁿ-1 (where n is the length of the register). That is the largest unsigned value a register can hold.
Jump if Above or Equal (unsigned comparison)
[edit | edit source]jae loc
CF = 0 or ZF = 1
Loads EIP
with the specified address, if the minuend
of previous cmp
instruction is greater than or equal to the subtrahend
.
jae
is the same as jge
, except that it performs an unsigned comparison.
Jump if Lesser
[edit | edit source]jl loc
The criterion required for a jl
is that SF
≠ OF
.
It loads EIP
with the specified address, if the criterion is met.
So either SF
or OF
can be set, but not both in order to satisfy this criterion.
If we take the sub
(which is basically what a cmp
does) instruction as an example, we have:
minuend
-subtrahend
With respect to sub
and cmp
there are several cases that fulfill this criterion:
minuend
<subtrahend
and the operation does not have overflowminuend
>subtrahend
and the operation has an overflow
In the first case SF
will be set but not OF
and in second case OF
will be set but not SF
since the overflow will reset the most significant bit to zero and thus preventing SF
being set.
The SF
≠ OF
criterion avoids the cases where:
minuend
>subtrahend
and the operation does not have overflowminuend
<subtrahend
and the operation has an overflowminuend
=subtrahend
In the first case neither SF
nor OF
are set, in the second case OF
will be set and SF
will be set since the overflow will reset the most significant bit to one and in the last case neither SF
nor OF
will be set.
Jump if Less or Equal
[edit | edit source]jle loc
SF
≠ OF
or ZF = 1
.
Loads EIP
with the specified address, if the minuend
of previous cmp
instruction is lesser than or equal to the subtrahend
.
See the jl
section for a more detailed description of the criteria.
Jump if Below (unsigned comparison)
[edit | edit source]jb loc
CF = 1
Loads EIP with the specified address, if first operand of previous CMP instruction is lesser than the second. jb
is the same as jl
, except that it performs an unsigned comparison.
mov rax, 0 ; rax ≔ 0
cmp rax, rbx ; rax ≟ rbx
jb loc ; always jumps, unless rbx is also 0
Jump if Below or Equal (unsigned comparison)
[edit | edit source]jbe loc
CF = 1 or ZF = 1
Loads EIP
with the specified address, if minuend
of previous cmp
instruction is lesser than or equal to the subtrahend
.
jbe
is the same as jle
, except that it performs an unsigned comparison.
Jump if Zero
[edit | edit source]jz loc
ZF = 1
Loads EIP
with the specified address, if the zero bit is set from a previous arithmetic expression.
jz
is identical to je
.
Jump if Not Zero
[edit | edit source]jnz loc
ZF = 0
Loads EIP
with the specified address, if the zero bit is not set from a previous arithmetic expression.
jnz
is identical to jne
.
Jump if Signed
[edit | edit source]js loc
SF = 1
Loads EIP
with the specified address, if the sign bit is set from a previous arithmetic expression.
Jump if Not Signed
[edit | edit source]jns loc
SF = 0
Loads EIP
with the specified address, if the sign bit is not set from a previous arithmetic expression.
Jump if Carry
[edit | edit source]jc loc
CF = 1
Loads EIP
with the specified address, if the carry bit is set from a previous arithmetic expression.
Jump if Not Carry
[edit | edit source]jnc loc
CF = 0
Loads EIP
with the specified address, if the carry bit is not set from a previous arithmetic expression.
Jump if Overflow
[edit | edit source]jo loc
OF = 1
Loads EIP
with the specified address, if the overflow bit is set on a previous arithmetic expression.
Jump if Not Overflow
[edit | edit source]jno loc
OF = 0
Loads EIP
with the specified address, if the overflow bit is not set on a previous arithmetic expression.
Jump if counter register is zero
[edit | edit source]jcxz loc
CX = 0
jecxz loc
ECX = 0
jrcxz loc
RCX = 0
Loads EIP
with the specified address if the counter register is zero.
Application
[edit | edit source]- The existence of this instruction makes the counter register particularly suitable for holding (high-level language) pointers: In most programming languages the “null pointer”, an invalid pointer, is implemented by the numeric value
0
. Usually, you do not want to dereference such a null pointer as the result will be bogus or even cause a GPF. By jumping away, withjecx
, to some code handling this error, you can avoid running into such a situation before you attempt to dereference the pointer value. You do not need an extratest ecx, ecx
. - If you are using the
loop
instruction to implement a loop, but it is possible the requested number of iteration is zero, you may want to insert ajecx
before the loop’s body. Otherwise,loop
will decrement zero, thus ending up doing 232 iterations.
Function Calls
[edit | edit source]call proc
Pushes the address of the instruction that follows the call
call, i.e. usually the next line in your source code, onto the top of the stack, and then jumps to the specified location.
This is used mostly for subroutines.
ret [val]
Pops the next value on the stack into EIP
, and then pops the specified number of bytes off the stack.
If val
is not supplied, the instruction will not pop any values off the stack after returning.
Loop Instructions
[edit | edit source]loop arg
The loop
instruction decrements ECX
and jumps to the address specified by arg
unless decrementing ECX
caused its value to become zero.
For example:
mov ecx, 5 ; ecx ≔ 5
head:
; the code here would be executed 5 times
loop head
loop
does not set any flags.
loopcc arg
These loop instructions decrement ECX
and jump to the address specified by arg
if their condition is satisfied (that is, a specific flag is set), unless decrementing ECX
caused its value to become zero.
loope
loop if equalloopne
loop if not equalloopnz
loop if not zeroloopz
loop if zero
That way, only testing for a non-zero ECX
can be combined with testing ZF
.
Other flags can not be tested for, say there is no loopnc
“loop while ECX
≠ 0 and CF
unset”.
Enter and Leave
[edit | edit source]enter arg
enter
creates a stack frame with the specified amount of space allocated on the stack.
leave
leave
destroys the current stack frame, and restores the previous frame.
Using Intel syntax this is equivalent to:
mov esp, ebp ; esp ≔ ebp
pop ebp
This will set EBP
and ESP
to their respective value before the function prologue began therefore reversing any modification to the stack that took place during the prologue.
Other Control Instructions
[edit | edit source]hlt
Halts the processor.
Execution will be resumed after processing next hardware interrupt, unless IF
is cleared.
nop
No operation. This instruction doesn't do anything, but wastes (an) instruction cycle(s) in the processor.
This instruction is often represented as an xchg
operation with the operands EAX
and EAX
(an operation without side-effects), because there is no designated opcode for doing nothing.
This just as a passing remark, so that you do not get confused with disassembled code.
lock
Asserts #LOCK prefix on next instruction.
wait
Waits for the FPU to finish its last calculation.