CHAPTER 5 - Jumps and branching
You should know a little about how instructions are processed by processor. It
fetches instruction in machine code, executes it, and then moves to next
instruction. This is repeaten until instruction int 20h
is reached.
In this chapter we will learn something about instructions which changes this
behaviour.
5.1. instruction pointer
Processor loads first instructions (it determines number of bytes the
instrution consists from), executes it and then moves to another instruction.
But how this mechanism works? Processor has a special word register "ip" which
holds address of currently executed instruction. After instruction is executed
processor adds it's size to "ip" and executes instruction on address in "ip".
Mechanism works like this:
- Loop
- Execute instruction on
ip
- size = size of instruction on
ip
- ip = ip + size
- Until instruction
int 20h
is found
NOTE: as with others pointers, ip
doesn't hold full address
of instruction, only offset part. Be we don't care about this now.
NOTE: "ip" stands for "instruction pointer".
5.2. Jumps
Register ip
is not like other registers (like ax
,
ah
,bp
...). It's contents can't be changed using
mov
instruction. mov ip,5
doesn't work.
But there is a special instruction which can change value in ip
register. It is jmp
("jmp" = "jump") instruction. This instruction
has one operand, new address for ip
register. So
jmp 5 has effect like mov ip,5
would if it were an
instruction. Example:
org 256
jmp Start
text db 'Text to output'
Start:
mov ah,9
mov dx,text
int 21h
int 20h
First instruction sets value of ip
to address of
mov ah,9
instruction (address is held in label Start
).
Thus processor won't try to execute bytes
defined by "Text to output" string and this program will work.
NOTE: of course, when ip
is changed by jmp
instruction, then size of this instruction is NOT added to it.
5.3. Comparing and conditonal jumps
If you can code any language already you should know branching, eg.
conditional execution of some parts of code. For example: say you want value
not greater than 10 in al
. So if value in al
register
is > 10, you will set al
to 10. This is branching - if some
condition is true then something is executed, otherwise it is not executed.
Assembly impletation of this mechanism is that when condition is false you will
jump over conditional code, when condition is true you will just cotinue
execution. It is as if C code:
if (condition)
ConditionalCode(); //this can be any C code, not just function call
would be writen this way:
if (!condition) goto LabelAfterConditionalCode;
ConditionalCode(); //this can be any C code, not just function call
LabelAfterConditionalCode:
First problem is how to decide whether condition is true. In assembly, there
is instruction which can compare two operands. It is cmp
. It's
operands follow same rules as mov
's operands (almost every
instruction follows these or very similar rules). So examples of comparing:
cmp ax,bx ; compare value of "ax" to value of "bx"
cmp al,byte [SomeLabel] ; comapre value of "al" to byte at SomeLabel
cmp ax,5 ; compare value of "ax" to 5
cmp ax,al ; wrong, operands have different size
This instructions checks whether first operand is same, greater or lesser than
second.
instruction: cmp
OK, we can compare, but how are results of comparison stored? CPU (processor)
has special register called "flags register" in which it stores results of
comparison (and some other things too). This register can't be accessed with
mov
or similar instructions (same like ip
), it's value
is set by cmp
instruction. Now you don't have to care HOW is result
of comparison stored in this register, you would need understand bit arithmetics.
register: flags
OK, we can compare, we know result is stored in flags
. Only thing
we need now is conditional jump itslef. Conditional jump is jump which is taken only
when condition specified by you is true (in flags register). It will be best
explained on example. We compare ax
to bx
(cmp ax,bx
). Now conditional jump can jump if ax
<
bx
, or when ax
= bx
, or when
ax
>= bx
etc.
These jumps are (op1 is first operand of cmp
, op2 is second):
je
- jump if op1 = op2 (op1 is "equal to" op2)
ja
- jump if op1 > op2 (op1 is "above" op2)
jb
- jump if op1 < op2 (op1 is "below" op2)
jae
- jump if op1 >= op2 (op1 is "above or equal to" op2)
jbe
- jump if op1 <= op2 (op1 is "below or equal to" op2)
Example code: (but don't try to compile it, it is not .COM executable, it is
just piece of code)
cmp ax,10
jbe AX_lesser_than_10
mov ax,10
AX_lesser_than_10:
this piece of code will check whether value in ax
is below or equal
to 10, and if not (if the value in ax
is above 10) it will set
ax
to 10. Corresponding C code is:
if (ax>10) ax=10;
or more similar to our assembly version:
if (ax <= 10) goto AX_lesser_than_10
ax=10;
AX_lesser_than_10:
Another example: get maximum of {ax,bx} and store it in ax:
cmp ax,bx
jae AX_already_contains_bigger_value
mov ax,bx
AX_already_contains_bigger_value:
So compare ax
to bx
, if it is bigger or equal then it
already contains the bigger value, we dont need to change anything. If
ax
is lesser than bx
then we must move value in
bx
(=bigger value) to ax
.
More complicated version: store maximum of {ax,bx} in cx:
cmp ax,bx
ja AX_bigger
mov cx,bx
jmp done
AX_bigger:
mov cx,ax
done:
so we compare ax
to bx
, then if ax
is
lesser than bx
jump won't be taken and we continue by
mov cx,bx
which stores bigger value in cx
as
wanted, and then jmp done
skips instructions used in case
ax
is bigger.
If ax
is bigger than bx
, then jmp AX_bigger
will be taked, so next instruction is mov cx,ax
which moves greater
value (in ax
) to cx
. You see, code was divided into two
"branches" one for ax>bx, other for ax<=bx.
Finally both branches goes to instruction behind done:
, and at this
place cx
always holds bigger value. By the way, there could be
jae
instead ja
, because for case when ax=bx both
branches have same effect.
instructions: je, ja, jb, jae, jbe
But what can we do if we want to jump when operands are NOT equal? We could do
something like this:
cmp ax,bx
je Same
jmp NotSame
Same:
...
NotSame:
but this is not needed because there are instructions which jumps when
condition is not true. These are jne
,jna
,
jnb
,jnae
and jnbe
. Instruction
jne
jumps when operands are not equal, jna
when first
operand is not above second operand etc., so:
cmp ax,bx
jne NotSame:
...
NotSame:
and ... part is executed only if value in ax is equal to value in bx.
NOTE: jna
is same as jbe
, jnb
is
same as jae
, jb
is same as jnae
,
ja
is same as jnbe
.
instructions: jne, jna, jnb, jnae, jnbe
NOTE: (important) many instruction change flags
register,
not only cmp
, so conditional jumps should be right behind
cmp
, no instructions between them.