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.
Of course, if you have an 80386 or later processor you needn't go through all this just to add two 32 bit values together, since the 80386 directly supports 32 bit operations. However, if you wanted to add two 64 bit integers together on the 80386, you would still need to use this technique.
You can extend this to any number of bits by using the 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.
You can easily synthesize any possible comparison from the sequence above, the following examples show how to do this. These examples do signed comparisons, substitute ja, jae, jb, and jbe for jg, jge, jl, and jle (respectively) to do unsigned comparisons.
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