short int, int,
and long int. On the PC, these are often 16 or 32 bit integers.
Although the 80x86 machine instructions limit you to processing eight, sixteen,
or thirty-two bit integers with a single instruction, you can always use
more than one instruction to process integers of any size you desire. If
you want 256 bit integer values, no problem. The following sections describe
how extended various arithmetic and logical operations from 16 or 32 bits
to as many bits as you please.add instruction adds two 8, 16, or 32 bit numbers[1].
After the execution of the add instruction, the 80x86 carry
flag is set if there is an overflow out of the H.O. bit of the sum. You
can use this information to do multiprecision addition operations. Consider
the way you manually perform a multidigit (multiprecision) addition operation:
289 289
+456 produces +456
---- ----
5 with carry 1.
Step 2: Add the next significant digits plus the carry:
1 (previous carry)
289 289
+456 produces +456
---- ----
5 45 with carry 1.
Step 3: Add the most significant digits plus the carry:
1 (previous carry)
289 289
+456 produces +456
---- ----
45 745
The 80x86 handles extended precision arithmetic in an identical fashion,
except instead of adding the numbers a digit at a time, it adds them a byte
or a word at a time. Consider the three-word (48 bit) addition operation
shown below:
The add instruction adds the L.O. words together. The adc
(add with carry) instruction adds all other word pairs together. The adc
instruction adds two operands plus the carry flag together producing a word
value and (possibly) a carry.
For example, suppose that you have two thirty-two bit values you wish to
add together, defined as follows:
X dword ? Y dword ?Suppose, also, that you want to store the sum in a third variable, Z, that is likewise defined with the
dword directive. The following
80x86 code will accomplish this task:
mov ax, word ptr X
add ax, word ptr Y
mov word ptr Z, ax
mov ax, word ptr X+2
adc ax, word ptr Y+2
mov word ptr Z+2, ax
Remember, these variables are declared with the dword directive.
Therefore the assembler will not accept an instruction of the form mov
ax, X because this instruction would attempt to load a 32 bit value
into a 16 bit register. Therefore this code uses the word ptr coercion operator
to coerce symbols X, Y, and Z to
16 bits. The first three instructions add the L.O. words of X
and Y together and store the result at the L.O. word of Z.
The last three instructions add the H.O. words of X and Y
together, along with the carry out of the L.O. word, and store the result
in the H.O. word of Z. Remember, address expressions of the
form "X+2" access the H.O. word of a 32 bit entity. This is due
to the fact that the 80x86 address space addresses bytes and it takes two
consecutive bytes to form a word.adc
instruction to add in the higher order words in the values. For example,
to add together two 128 bit values, you could use code that looks something
like the following:
BigVal1 dword 0,0,0,0 ;Four double words in 128 bits!
BigVal2 dword 0,0,0,0
BigVal3 dword 0,0,0,0
.
.
.
mov eax, BigVal1 ;No need for dword ptr operator since
add eax, BigVal2 ; these are dword variables.
mov BigVal3, eax
mov eax, BigVal1+4 ;Add in the values from the L.O.
adc eax, BigVal2+4 ; entity to the H.O. entity using
mov BigVal3+4, eax ; the ADC instruction.
mov eax, BigVal1+8
adc eax, BigVal2+8
mov BigVal3+8, eax
mov eax, BigVal1+12
adc eax, BigVal2+12
mov BigVal3+12, eax
add operation, You use the sub instruction on the L.O.
byte/word/double word and the sbb instruction on the high order values.
The following example demonstrates a 32 bit subtraction using the 16 bit
registers on the 8086:
var1 dword ?
var2 dword ?
diff dword ?
mov ax, word ptr var1
sub ax, word ptr var2
mov word ptr diff, ax
mov ax, word ptr var1+2
sbb ax, word ptr var2+2
mov word ptr diff+2, ax
The following example demonstrates a 128-bit subtraction using the 80386
32 bit register set:
BigVal1 dword 0,0,0,0 ;Four double words in 128 bits!
BigVal2 dword 0,0,0,0
BigVal3 dword 0,0,0,0
.
.
.
mov eax, BigVal1 ;No need for dword ptr operator since
sub eax, BigVal2 ; these are dword variables.
mov BigVal3, eax
mov eax, BigVal1+4 ;Subtract the values from the L.O.
sbb eax, BigVal2+4 ; entity to the H.O. entity using
mov BigVal3+4, eax ; the SUB and SBB instructions.
mov eax, BigVal1+8
sbb eax, BigVal2+8
mov BigVal3+8, eax
mov eax, BigVal1+12
sbb eax, BigVal2+12
mov BigVal3+12, eax
cmp
and sub instructions perform the same operation, at
least as far as the flags are concerned, you'd probably guess that you could
use the sbb instruction to synthesize an extended precision
comparison; however, you'd only be partly right. There is, however, a better
way.
; This sequence transfers control to location "IsGreater" if
; QwordValue > QwordValue2. It transfers control to "IsLess" if
; QwordValue < QwordValue2. It falls though to the instruction
; following this sequence if QwordValue = QwordValue2. To test for
; inequality, change the "IsGreater" and "IsLess" operands to "NotEqual"
; in this code.
mov eax, dword ptr QWordValue+4 ;Get H.O. dword
cmp eax, dword ptr QWordValue2+4
jg IsGreater
jl IsLess
mov eax, dword ptr QWordValue
cmp eax, dword ptr QWordValue2
jg IsGreater
jl IsLess
To compare unsigned values, simply use the ja and jb instructions in place
of jg and jl.
QW1 qword ?
QW2 qword ?
dp textequ <dword ptr>
; 64 bit test to see if QW1 < QW2 (signed).
; Control transfers to "IsLess" label if QW1 < QW2. Control falls
; through to the next statement if this is not true.
mov eax, dp QW1+4 ;Get H.O. dword
cmp eax, dp QW2+4
jg NotLess
jl IsLess
mov eax, dp QW1 ;Fall through to here if H.O.
cmp eax, dp QW2 ; dwords are equal.
jl IsLess
NotLess:
; 64 bit test to see if QW1 <= QW2 (signed).
mov eax, dp QW1+4 ;Get H.O. dword
cmp eax, dp QW2+4
jg NotLessEq
jl IsLessEq
mov eax, dp QW1
cmp eax, dword ptr QW2
jle IsLessEq
NotLessEQ:
; 64 bit test to see if QW1 >QW2 (signed).
mov eax, dp QW1+4 ;Get H.O. dword
cmp eax, dp QW2+4
jg IsGtr
jl NotGtr
mov eax, dp QW1 ;Fall through to here if H.O.
cmp eax, dp QW2 ; dwords are equal.
jg IsGtr
NotGtr:
; 64 bit test to see if QW1 >= QW2 (signed).
mov eax, dp QW1+4 ;Get H.O. dword
cmp eax, dp QW2+4
jg IsGtrEq
jl NotGtrEq
mov eax, dp QW1
cmp eax, dword ptr QW2
jge IsGtrEq
NotGtrEq:
; 64 bit test to see if QW1 = QW2 (signed or unsigned). This code branches
; to the label "IsEqual" if QW1 = QW2. It falls through to the next instruction
; if they are not equal.
mov eax, dp QW1+4 ;Get H.O. dword
cmp eax, dp QW2+4
jne NotEqual
mov eax, dp QW1
cmp eax, dword ptr QW2
je IsEqual
NotEqual:
; 64 bit test to see if QW1 <> QW2 (signed or unsigned). This code branches
; to the label "NotEqual" if QW1 <> QW2. It falls through to the next
; instruction if they are equal.
mov eax, dp QW1+4 ;Get H.O. dword
cmp eax, dp QW2+4
jne NotEqual
mov eax, dp QW1
cmp eax, dword ptr QW2
jne NotEqual