Unit - 3
Unit - 3
The 8086 Instruction 8086 Instruction Format vary from 1 to 6 bytes in length.
Fig. 6.8 shows the instruction formats for 1 to 6 bytes instructions. As shown
in the Fig. 6.8, displacements and operands may be either 8-bits or 16-bits
long depending on the instruction. The opcode and the addressing mode is
specified using first two bytes of an instruction.
• No additional byte
• Two byte EA (For direct addressing only).
• One or two byte displacement
• One or two byte immediate operand
• One or two byte displacement followed by a one or two byte immediate
operand
• Two byte displacement and a two byte segment address (for direct
intersegment addressing only).
Most of the opcodes in 8086 has a special 1-bit indicates. They are :
W-bit : Some instructions of 8086 can operate on byte or a word. The W-bit
in the opcode of such instruction specify whether instruction is a byte
instruction (W = 0) or a word instruction (W = 1).
D-bit : The D-bit in the opcode of the instruction indicates that the register
specified within the instruction is a source register (D = 0) or destination
register (D =1).
V-bit : V-bit decides the number of shifts for rotate and shift instructions. If V
= 0, then count = 1; if V = 1, the count is in CL register. For example, if V = 1
and CL = 2 then shift or rotate instruction shifts or rotates 2-bits
Z-bit : It is used for string primitives such as REP for comparison with ZF Flag.
(Refer Appendix A for instruction formats)
As seen from the Fig. 6.8 if an instruction has two opcode/addressing mode
bytes, then the second byte is of one of the following two forms .
where Mod, Reg and R/M fields specify operand as described in the following
tables.
Addressing Modes
Addressing Modes– The term addressing modes refers to the way in which
the operand of an instruction is specified. The addressing mode specifies a
rule for interpreting or modifying the address field of the instruction before the
operand is actually executed.
Addressing modes for 8086 instructions are divided into two
categories:
1) Addressing modes for data
2) Addressing modes for branch
The 8086 memory addressing modes provide flexible access to memory,
allowing you to easily access variables, arrays, records, pointers, and other
complex data types. The key to good assembly language programming is the
proper use of memory addressing modes.
An assembly language program instruction consists of two parts
Example: MOV AL, 35H (move the data 35H into AL register)
• Register mode: In register addressing the operand is placed in one
of 8 bit or 16 bit general purpose registers. The data is in the
register that is specified by the instruction.
Here one register reference is required to access the data.
Assembler Directives
Definition: Assembler directives are the instructions used by the
assembler at the time of assembling a source program. More specifically,
we can say, assembler directives are the commands or instructions that
control the operation of the assembler.
Assembler directives are the instructions provided to the assembler, not
the processor as the processor has nothing to do with these instructions.
These instructions are also known as pseudo-instructions or pseudo-
opcode.
Now the question arises what assembler directives specifically do?
DUP: Duplicate
DUP allows initialization of multiple locations and assigning of values to
them. This allows storing of repeated characters or variables in different
locations.
PROC: Procedure
It defines the starting of a procedure/subroutine.
The statements within the segment are nothing but the program code.
EVEN: It is used to inform the assembler to align the data beginning from an
even address.
As data specified with an odd starting address requires 2 byte accessing.
Thus using this directive, data can be aligned with an even starting
address.
PTR: Pointer
This directive shows information regarding the size of the operand.
This shows legal near jump to BX.
2 OR OR operand1, operand2
The first operand in all the cases could be either in register or in memory. The second
operand could be either in register/memory or an immediate (constant) value.
However, memory-to-memory operations are not possible. These instructions
compare or match bits of the operands and set the CF, OF, PF, SF and ZF flags.
Let's take up another example. If you want to check whether a given number is odd
or even, a simple test would be to check the least significant bit of the number. If this
is 1, the number is odd, else the number is even.
Assuming the number is in AL register, we can write −
AND AL, 01H ; ANDing with 0000 0001
JZ EVEN_NUMBER
Example
Live Demo
section .text
global _start ;must be declared for using gcc
evnn:
outprog:
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
section .data
even_msg db 'Even Number!' ;message showing even number
len1 equ $ - even_msg
When the above code is compiled and executed, it produces the following result −
Even Number!
Change the value in the ax register with an odd digit, like −
mov ax, 9h ; getting 9 in the ax
The OR Instruction
The OR instruction is used for supporting logical expression by performing bitwise
OR operation. The bitwise OR operator returns 1, if the matching bits from either or
both operands are one. It returns 0, if both the bits are zero.
For example,
Operand1: 0101
Operand2: 0011
----------------------------
After OR -> Operand1: 0111
The OR operation can be used for setting one or more bits. For example, let us
assume the AL register contains 0011 1010, you need to set the four low-order bits,
you can OR it with a value 0000 1111, i.e., FH.
OR BL, 0FH ; This sets BL to 0011 1111
Example
The following example demonstrates the OR instruction. Let us store the value 5 and
3 in the AL and the BL registers, respectively, then the instruction,
OR AL, BL
section .text
global _start ;must be declared for using gcc
mov [result], al
mov eax, 4
mov ebx, 1
mov ecx, result
mov edx, 1
int 0x80
outprog:
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
section .bss
result resb 1
When the above code is compiled and executed, it produces the following result −
7
Syntax
The INC instruction has the following syntax −
INC destination
The operand destination could be an 8-bit, 16-bit or 32-bit operand.
Example
INC EBX ; Increments 32-bit register
INC DL ; Increments 8-bit register
INC [count] ; Increments the count variable
Syntax
The DEC instruction has the following syntax −
DEC destination
The operand destination could be an 8-bit, 16-bit or 32-bit operand.
Example
segment .data
count dw 0
value db 15
segment .text
inc [count]
dec [value]
Syntax
The ADD and SUB instructions have the following syntax −
ADD/SUB destination, source
The ADD/SUB instruction can take place between −
• Register to register
• Memory to register
• Register to memory
• Register to constant data
• Memory to constant data
However, like other instructions, memory-to-memory operations are not possible
using ADD/SUB instructions. An ADD or SUB operation sets or clears the overflow
and carry flags.
Example
The following example will ask two digits from the user, store the digits in the EAX
and EBX register, respectively, add the values, store the result in a memory location
'res' and finally display the result.
SYS_EXIT equ 1
SYS_READ equ 3
SYS_WRITE equ 4
STDIN equ 0
STDOUT equ 1
segment .data
segment .bss
num1 resb 2
num2 resb 2
res resb 1
section .text
global _start ;must be declared for using gcc
exit:
When the above code is compiled and executed, it produces the following result −
Enter a digit:
3
Please enter a second digit:
4
The sum is:
7
The program with hardcoded variables −
Live Demo
section .text
global _start ;must be declared for using gcc
mov ecx,sum
mov edx, 1
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
section .data
msg db "The sum is:", 0xA,0xD
len equ $ - msg
segment .bss
sum resb 1
When the above code is compiled and executed, it produces the following result −
The sum is:
7
Syntax
The syntax for the MUL/IMUL instructions is as follows −
MUL/IMUL multiplier
Multiplicand in both cases will be in an accumulator, depending upon the size of the
multiplicand and the multiplier and the generated product is also stored in two
registers depending upon the size of the operands. Following section explains MUL
instructions with three different cases −
Sr.No. Scenarios
1
When two bytes are multiplied −
The multiplicand is in the AL register, and the multiplier is a byte in the memory or
in another register. The product is in AX. High-order 8 bits of the product is stored
in AH and the low-order 8 bits are stored in AL.
2
When two one-word values are multiplied −
The multiplicand should be in the AX register, and the multiplier is a word in
memory or another register. For example, for an instruction like MUL DX, you must
store the multiplier in DX and the multiplicand in AX.
The resultant product is a doubleword, which will need two registers. The high-
order (leftmost) portion gets stored in DX and the lower-order (rightmost) portion
gets stored in AX.
3
When two doubleword values are multiplied −
When two doubleword values are multiplied, the multiplicand should be in EAX and
the multiplier is a doubleword value stored in memory or in another register. The
product generated is stored in the EDX:EAX registers, i.e., the high order 32 bits
gets stored in the EDX register and the low order 32-bits are stored in the EAX
register.
Example
MOV AL, 10
MOV DL, 25
MUL DL
...
MOV DL, 0FFH ; DL= -1
MOV AL, 0BEH ; AL = -66
IMUL DL
Example
The following example multiplies 3 with 2, and displays the result −
Live Demo
section .text
global _start ;must be declared for using gcc
_start: ;tell linker entry point
mov al,'3'
sub al, '0'
mov [res], al
mov ecx,msg
mov edx, len
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
mov ecx,res
mov edx, 1
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
section .data
msg db "The result is:", 0xA,0xD
len equ $- msg
segment .bss
res resb 1
When the above code is compiled and executed, it produces the following result −
The result is:
6
Syntax
The format for the DIV/IDIV instruction −
DIV/IDIV divisor
The dividend is in an accumulator. Both the instructions can work with 8-bit, 16-bit or
32-bit operands. The operation affects all six status flags. Following section explains
three cases of division with different operand size −
Sr.No. Scenarios
1
When the divisor is 1 byte −
The dividend is assumed to be in the AX register (16 bits). After division, the
quotient goes to the AL register and the remainder goes to the AH register.
2
When the divisor is 1 word −
The dividend is assumed to be 32 bits long and in the DX:AX registers. The
high-order 16 bits are in DX and the low-order 16 bits are in AX. After division,
the 16-bit quotient goes to the AX register and the 16-bit remainder goes to
the DX register.
3
When the divisor is doubleword −
The dividend is assumed to be 64 bits long and in the EDX:EAX registers.
The high-order 32 bits are in EDX and the low-order 32 bits are in EAX. After
division, the 32-bit quotient goes to the EAX register and the 32-bit remainder
goes to the EDX register.
Example
The following example divides 8 with 2. The dividend 8 is stored in the 16-bit AX
register and the divisor 2 is stored in the 8-bit BL register.
Live Demo
section .text
global _start ;must be declared for using gcc
mov [res], ax
mov ecx,msg
mov edx, len
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
mov ecx,res
mov edx, 1
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
section .data
msg db "The result is:", 0xA,0xD
len equ $- msg
segment .bss
res resb 1
When the above code is compiled and executed, it produces the following result −
The result is:
4
Assembly - Loops
The JMP instruction can be used for implementing loops. For example, the following
code snippet can be used for executing the loop-body 10 times.
MOV CL, 10
L1:
<LOOP-BODY>
DEC CL
JNZ L1
The processor instruction set, however, includes a group of loop instructions for
implementing iteration. The basic LOOP instruction has the following syntax −
LOOP label
Where, label is the target label that identifies the target instruction as in the jump
instructions. The LOOP instruction assumes that the ECX register contains the
loop count. When the loop instruction is executed, the ECX register is decremented
and the control jumps to the target label, until the ECX register value, i.e., the counter
reaches the value zero.
The above code snippet could be written as −
mov ECX,10
l1:
<loop body>
loop l1
Example
The following program prints the number 1 to 9 on the screen −
Live Demo
section .text
global _start ;must be declared for using gcc
l1:
mov [num], eax
mov eax, 4
mov ebx, 1
push ecx
When the above code is compiled and executed, it produces the following result −
123456789: