and, or,
xor, test,
and not
; the rotates are ror, rol,
rcr,
and rcl
; the shift instructions are shl/sal,
shr,
and sar
. The 80386 and later processors provide
an even richer set of operations. These are bt, bts, btr, btc
,
bsf, bsr
, shld, shrd
, and the conditional set
instructions (setcc
).and,
not, or,
and xor
instructions do the following:
and dest, source ;dest := dest and source or dest, source ;dest := dest or source xor dest, source ;dest := dest xor source not dest ;dest := not dest The specific variations are and reg, reg and mem, reg and reg, mem and reg, immediate data and mem, immediate data and eax/ax/al, immediate data or uses the same formats as AND xor uses the same formats as AND not register not memExcept
not
, these instructions affect the flags as follows:
not
instruction does not affect any flags.and
instruction sets the zero flag if the two operands do not
have any ones in corresponding bit positions (since this would produce a
zero result); for example, if the source operand contained a single one
bit, then the zero flag will be set if the corresponding destination bit
is zero, it will be one otherwise. The or
instruction will
only set the zero flag if both operands contain zero. The xor
instruction will set the zero flag only if both operands are equal. Notice
that the xor
operation will produce a zero result if and only
if the two operands are equal. Many programmers commonly use this fact to
clear a sixteen bit register to zero since an instruction of the form
xor reg16, reg16is shorter than the comparable
mov reg,0
instruction.and
, or
,
and xor
instructions provide special forms involving the accumulator
register and immediate data. These forms are shorter and sometimes faster
than the general "register, immediate" forms. Although one does
not normally think of operating on signed data with these instructions,
the 80x86 does provide a special form of the "reg/mem, immediate"
instructions that sign extend a value in the range -128..+127 to sixteen
or thirty-two bits, as necessary.and
instruction to set selected bits to zero
in the destination operand. This is known as masking out data; see for more
details. Likewise, you can use the or
instruction to force
certain bits to one in the destination operand; see Chapter Nine for the
details. You can use these instructions, along with the shift and rotate
instructions described next, to pack and unpack data. shl
and sal
are the same instruction): shl
(shift
left), sal
(shift arithmetic left), shr
(shift
right), and sar
(shift arithmetic right). The 80386 and later
processors provide two additional shifts: shld
and shrd
.
shl dest, count sal dest, count shr dest, count sar dest, count
Dest
is the value to shift and count
specifies
the number of bit positions to shift. For example, the shl
instruction shifts the bits in the destination operand to the left the number
of bit positions specified by the count
operand. The shld
and shrd
instructions use the format:
shld dest, source, count shrd dest, source, countThe specific forms for these instructions are
shl reg, 1 shl mem, 1 shl reg, imm (2) shl mem, imm (2) shl reg, cl shl mem, cl sal is a synonym for shl and uses the same formats. shr uses the same formats as shl. sar uses the same formats as shl. shld reg, reg, imm (3) shld mem, reg, imm (3) shld reg, reg, cl (3) shld mem, reg, cl (3) shrd uses the same formats as shld. 2- This form is available on 80286 and later processors only. 3- This form is available on 80386 and later processors only.For 8088 and 8086 CPUs, the number of bits to shift is either "1" or the value in
cl
. On 80286 and later processors you can use
an eight bit immediate constant. Of course, the value in cl
or the immediate constant should be less than or equal to the number of
bits in the destination operand. It would be a waste of time to shift left
al
by nine bits (eight would produce the same result, as you
will soon see). Algorithmically, you can think of the shift operations with
a count other than one as follows:
for temp := 1 to count do shift dest, 1There are minor differences in the way the shift instructions treat the overflow flag when the count is not one, but you can ignore this most of the time.
shl, sal, shr,
and sar
instructions work on
eight, sixteen, and thirty-two bit operands. The shld
and shrd
instructions work on 16 and 32 bit destination operands only.shl
and sal
mnemonics are synonyms. They represent
the same instruction and use identical binary encodings. These instructions
move each bit in the destination operand one bit position to the left the
number of times specified by the count operand. Zeros fill vacated positions
at the L.O. bit; the H.O. bit shifts into the carry flag:The shl/sal
instruction sets the condition code bits as
follows:
shl
instruction doesn't
affect any flags.
shl/sal
instruction.
al
and ah
that
you want to combine. You could use the following code to do this:
shl ah, 4 ;This form requires an 80286 or later or al, ah ;Merge in H.O. four bits.Of course,
al
must contain a value in the range 0..F for this
code to work properly (the shift left operation automatically clears the
L.O. four bits of ah
before the or
instruction).
If the H.O. four bits of al
are not zero before this operation,
you can easily clear them with an and
instruction:
shl ah, 4 ;Move L.O. bits to H.O. position. and al, 0Fh ;Clear H.O. four bits. or al, ah ;Merge the bits.Since shifting an integer value to the left one position is equivalent to multiplying that value by two, you can also use the shift left instruction for multiplication by powers of two:
shl ax, 1 ;Equivalent to AX*2 shl ax, 2 ;Equivalent to AX*4 shl ax, 3 ;Equivalent to AX*8 shl ax, 4 ;Equivalent to AX*16 shl ax, 5 ;Equivlaent to AX*32 shl ax, 6 ;Equivalent to AX*64 shl ax, 7 ;Equivalent to AX*128 shl ax, 8 ;Equivalent to AX*256 etc.Note that
shl ax, 8
is equivalent to the following two instructions:
mov ah, al mov al, 0The
shl/sal
instruction multiplies both signed and unsigned
values by two for each shift. This instruction sets the carry flag if the
result does not fit in the destination operand (i.e., unsigned overflow
occurs). Likewise, this instruction sets the overflow flag if the signed
result does not fit in the destination operation. This occurs when you shift
a zero into the H.O. bit of a negative number or you shift a one into the
H.O. bit of a non-negative number.sar
instruction shifts all the bits in the destination
operand to the right one bit, replicating the H.O. bit:The sar
instruction sets the flag bits as follows:
sar
instruction doesn't
affect any flags.
sar
instruction.
sar
instruction's main purpose is to perform a signed division
by some power of two. Each shift to the right divides the value by two.
Multiple right shifts divide the previous shifted result by two, so multiple
shifts produce the following results:
sar ax, 1 ;Signed division by 2 sar ax, 2 ;Signed division by 4 sar ax, 3 ;Signed division by 8 sar ax, 4 ;Signed division by 16 sar ax, 5 ;Signed division by 32 sar ax, 6 ;Signed division by 64 sar ax, 7 ;Signed division by 128 sar ax, 8 ;Signed division by 256There is a very important difference between the
sar
and idiv
instructions. The idiv instruction always truncates towards zero while sar
truncates results toward the smaller result. For positive results, an arithmetic
shift right by one position produces the same result as an integer division
by two. However, if the quotient is negative, idiv
truncates
towards zero while sar
truncates towards negative infinity.
The following examples demonstrate the difference:
mov ax, -15 cwd mov bx, 2 idiv ;Produces -7 mov ax, -15 sar ax, 1 ;Produces -8Keep this in mind if you use
sar
for integer division operations.sar ax, 8
instruction effectively copies ah
into al
and then sign extends al
into ax
.
This is because sar ax, 8
will shift ah
down into
al
but leave a copy of ah
's H.O. bit in all the
bit positions of ah
. Indeed, you can use the sar instruction
on 80286 and later processors to sign extend one register into another.
The following code sequences provide examples of this usage:
; Equivalent to CBW: mov ah, al sar ah, 7 ; Equivalent to CWD: mov dx, ax sar dx, 15 ; Equivalent to CDQ: mov edx, eax sar edx, 31Of course it may seem silly to use two instructions where a single instruction might suffice; however, the
cbw, cwd,
and cdq
instructions only sign extend al
into ax, ax
into
dx:ax,
and eax
into edx:eax
. Likewise,
the movsx instruction copies its sign extended operand into a destination
operand twice the size of the source operand. The sar
instruction
lets you sign extend one register into another register of the same size,
with the second register containing the sign extension bits:
; Sign extend bx into cx:bx mov cx, bx sar cx, 15
shr
instruction shifts all the bits in the destination
operand to the right one bit shifting a zero into the H.O. bit:The shr
instruction sets the flag bits as follows:
shr
instruction doesn't
affect any flags.
shr
instruction.
al
register, leaving the H.O. nibble in ah
and the L.O. nibble
in al
. You could use the following code to do this:
mov ah, al ;Get a copy of the H.O. nibble shr ah, 4 ;Move H.O. to L.O. and clear H.O. nibble and al, 0Fh ;Remove H.O. nibble from alSince shifting an unsigned integer value to the right one position is equivalent to dividing that value by two, you can also use the shift right instruction for division by powers of two:
shr ax, 1 ;Equivalent to AX/2 shr ax, 2 ;Equivalent to AX/4 shr ax, 3 ;Equivalent to AX/8 shr ax, 4 ;Equivalent to AX/16 shr ax, 5 ;Equivlaent to AX/32 shr ax, 6 ;Equivalent to AX/64 shr ax, 7 ;Equivalent to AX/128 shr ax, 8 ;Equivalent to AX/256 etc.Note that
shr ax, 8
is equivalent to the following two instructions:
mov al, ah mov ah, 0Remember that division by two using
shr
only works for unsigned
operands. If ax
contains -1 and you execute shr ax, 1
the result in ax
will be 32767 (7FFFh), not -1 or zero
as you would expect. Use the sar
instruction if you need to
divide a signed integer by some power of two.shld
and shrd
instructions provide double
precision shift left and right operations, respectively. These instructions
are available only on 80386 and later processors. Their generic forms are
shld operand1, operand2, immediate shld operand1, operand2, cl shrd operand1, operand2, immediate shrd operand1, operand2, cl
Operand
2 must be a sixteen or thirty-two bit register. Operand
1
can be a register or a memory location. Both operands must be the same size.
The immediate operand can be a value in the range zero through n-1, where
n is the number of bits in the two operands; it specifies the number of
bits to shift.shld
instruction shifts bits in operand1 to the left. The
H.O. bit shifts into the carry flag and the H.O. bit of operand
2
shifts into the L.O. bit of operand
1. Note that this instruction
does not modify the value of operand2, it uses a temporary copy of operand2
during the shift. The immediate operand specifies the number of bits to
shift. If the count is n, then shld
shifts bit n-1 into the
carry flag. It also shifts the H.O. n bits of operand2 into the L.O. n bits
of operand1. Pictorially, the shld
instruction is: The shld
instruction sets the flag bits as follows:
mov ax, Value4 ;Get H.O. nibble shld bx, ax, 4 ;Copy H.O. bits of AX to BX. mov ax, Value3 ;Get nibble #2. shld bx, ax, 4 ;Merge into bx. mov ax, Value2 ;Get nibble #1. shld bx, ax, 4 ;Merge into bx. mov ax, Value1 ;Get L.O. nibble shld bx, ax, 4 ;BX now contains all four nibbles.The
shrd
instruction is similar to shld
except,
of course, it shifts its bits right rather than left. To get a clear picture
of the shrd
instruction, consider:The shrd
instruction sets the flag bits as follows:
shrd
instruction doesn't
affect any flags.
Operan
d2 could be a memory location. Intel designed these
instructions to allow fast multiprecision (64 bits, or more) shifts. shrd
instruction is marginally more useful than shld
for packing data. For example, suppose that ax
contains a value
in the range 0..99 representing a year (1900..1999), bx
contains
a value in the range 1..31 representing a day, and cx
contains
a value in the range 1..12 representing a month (see Chapter One). You can
easily use the shrd instruction to pack this data into dx
as
follows:
shrd dx, ax, 7 shrd dx, bx, 5 shrd dx, cx, 4
rcl
(rotate through carry
left), rcr
(rotate through carry right), rol
(rotate
left), and ror
(rotate right). These instructions all take
the forms:
rcl dest, count rol dest, count rcr dest, count ror dest, countThe specific forms are
rcl reg, 1 rcl mem, 1 rcl reg, imm (2) rcl mem, imm (2) rcl reg, cl rcl mem, cl rol uses the same formats as rcl. rcr uses the same formats as rcl. ror uses the same formats as rcl. 2- This form is avialable on 80286 and later processors only.
rcl
(rotate through carry left), as its name implies, rotates
bits to the left, through the carry flag, and back into bit zero on the
right:Note that if you rotate through carry an object n+1 times, where n is
the number of bits in the object, you wind up with your original value.
Keep in mind, however, that some flags may contain different values after
n+1 rcl
operations.
The rcl
instruction sets the flag bits as follows:
rcl
sets the overflow flag if
the sign changes as a result of the rotate. If the count is not one, the
overflow flag is undefined.
rcl
instruction does not modify the zero, sign, parity,
or auxiliary carry flags.
rcl
operation. If you need to
test one of these flags after an rcl
operation, test the carry
and overflow flags first (if necessary) then compare the result to zero
to set the other flags.rcr
(rotate through carry right) instruction is the complement
to the rcl
instruction. It shifts its bits right through the
carry flag and back into the H.O. bit:This instruction sets the flags in a manner analogous to rcl
:
rcr
sets the overflow flag
if the sign changes (meaning the values of the H.O. bit and carry flag were
not the same before the execution of the instruction). However, if the count
is not one, the value of the overflow flag is undefined.
rcr
instruction does not affect the zero, sign, parity,
or auxiliary carry flags.
rol
instruction is similar to the rcl
instruction
in that it rotates its operand to the left the specified number of bits.
The major difference is that rol
shifts its operand's H.O.
bit, rather than the carry, into bit zero. Rol
also copies
the output of the H.O. bit into the carry flag:The rol
instruction sets the flags identically to rcl
.
Other than the source of the value shifted into bit zero, this instruction
behaves exactly like the rcl
instruction. Don't forget the
warning about the flags!
Like shl
, the rol
instruction is often useful
for packing and unpacking data. For example, suppose you want to extract
bits 10..14 in ax
and leave these bits in bits 0..4. The following
code sequences will both accomplish this:
shr ax, 10 and ax, 1Fh rol ax, 6 and ax, 1Fh
ror
instruction relates to the rcr
instruction
in much the same way that the rol
instruction relates to rcl
.
That is, it is almost the same operation other than the source of the input
bit to the operand. Rather than shifting the previous carry flag into the
H.O. bit of the destination operation, ror
shifts bit zero
into the H.O. bit:The ror
instruction sets the flags identically to rcr
.
Other than the source of the bit shifted into the H.O. bit, this instruction
behaves exactly like the rcr
instruction. Don't forget the
warning about the flags!