Decimal arithmetic instructions

In about 15 years of Assembly development and reverse engineering software, I encountered these instructions exactly once, and that was in the college. However, it would be right to mention them, for a few reasons:

  • Instructions like AAM and AAD may sometimes be used as a smaller variant of multiplication and division, since they allow immediate operand. They're smaller as they allow generation of smaller code due to their encoding.
  • Sequences like AAD 0 (which is division by zero) may be used as an exception trigger in certain protection schemes.
  • Not mentioning them would be historically wrong.
Decimal arithmetic instructions are illegal on 64-bit platforms.

First of all, what is BCD? It is Binary coded decimal (BCD) and is, in fact, an attempt to ease the conversion of binary representations of numbers to their ASCII equivalent and vice versa, as well as adding the ability to perform basic arithmetic operations on decimal numbers represented in a hexadecimal form (not their hexadecimal equivalents!).

There are two types of BCD: packed and unpacked. Packed BCD represents a decimal number using nibbles of a single byte. For example, the number 12 would be represented as 0x12. Unpacked BCD, on the other hand, uses bytes for representation of individual digits (for example, 12 converts to 0x0102).

However, given the fact that these instructions have not been changed since their first appearance, they only operate on values stored in a single byte, for packed BCD, or values stored in a single word, for unpacked BCD. More than this, these values should be stored only in the AL register for packed BCD and the AX register (or, to say it in a more precise way, in the AH:AL pair) for unpacked BCD.

There are only six BCD instructions:

  • Decimal Adjust after Addition (DAA): This instruction is specific to packed BCD. Since the addition of two packed BCD numbers would not necessarily result in a valid packed BCD number, the invocation of DAA fixes the problem by making the adjustments needed for converting a result into a proper packed BCD value. For example, let's add 12 and 18. Normally, the result would be 30, but if we add 0x12 and 0x18, the result would be 0x2a. The following example illustrates the procedure for such a calculation:
mov al, 0x12   ; AL = 0x12, which is packed BCD 
; representation of 12
add al, 0x18 ; Add BCD representation of 18,
; which would result in 0x2a

daa ; Adjust. AL would contain 0x30 after this instruction,
; which is the BCD representation of 30
  • Decimal Adjust after Subtraction (DAS): This instruction performs similar adjustments after subtracting two packed BCD numbers. Let's add some more lines to the preceding code (AL still contains 0x30):

sub al, 0x03  ; We are subtracting 3 from 30, however, 
; the result of 0x30 - 0x03
; would be 0x2d
das ; This instruction sets AL to 0x27,
; which is the packed BCD

; representation of 27.
  • ASCII Adjust after Addition (AAA): This instruction is similar to DAA, yet it works on unpacked BCD numbers (meaning, the AX register). Let's look at the following example, where we still add 18 to 12, but we do that with the unpacked BCD:
mov ax, 0x0102  ; 0x0102 is the unpacked BCD representation of 12
add ax, 0x0108 ; same for 18
; The result of the addition would be
; 0x020a - far from being 0x0300

aaa ; Converts the value of AX register to 0x0300

The resulting value may easily be converted to the ASCII representation by adding 0x3030.

  • ASCII Adjust after Subtraction (AAS): This instruction is similar to DAS, but operates on unpacked BCD numbers. We may continue to add code to the preceding example (The AX register still has the value of 0x0300). Let's subtract 3, which should, at the end, give us the value of 0x0207:
sub ax, 0x0003  ; AX now contains 0x02fd
aas ; So we convert it to unpacked BCD
; representation, but...
; AX becomes 0x0107, but as we know,
; 30 - 3 != 17...

What went wrong then? In fact, nothing went wrong; it is just that the internal implementation of the AAS instruction caused carry (and, as we may see in a debugger, the CF is in deed set) or, to be more precise, a borrow occurred. That is why it is better for our convenience to finalize this with the following:

adc ah, 0  ; Adds the value of CF to AH

We end up with 0x0207, which is the unpacked BCD representation of 27--exactly the result we were expecting.

  • ASCII Adjust AX after Multiply (AAM): Result of the multiplication of two unpacked BCD numbers, as well, requires certain adjustments to be made in order to be in an unpacked BCD form. However, what we have to remember first of all is the size limitation implied by these operations. As we are limited to the AX register, the maximum value of a multiplicand is 9 (or 0x09), meaning that, being limited to AX with the resulting value, we are limited to one byte with multiplicands. Let's say we want to multiply 8 by 4 (which would be 0x08 * 0x04); naturally, the result would be 0x20 (the hexadecimal equivalent of 32), which is not even close to being an unpacked BCD represented number. The aam instruction solves this problem by converting the value of the AL register to the unpacked BCD format and stores it in AX:
mov al, 4 
mov bl, 8
mul bl ; AX becomes 0x0020
aam ; Converts the value of AX to the
; corresponding unpacked BCD form. Now the AX
; register equals to 0x0302

As we see, the multiplication of two unpacked BCD bytes results in an unpacked BCD word.

  • ASCII Adjust AX before Division (AAD): This is exactly as the name of the instruction suggests--it should adjust the value of the AX register before division. The size limitations are just the same as in AAM. The AX register still contains 0x0302 after the previous example, so let's divide it by 4:
mov bl, 4
aad ; Adjust AX. The value changes from 0x0302 to 0x0020
div bl ; Perform the division itself
; AL register contains the result - 0x08

As we see, although these instructions may seem to be somewhat convenient, there are better ways to convert numbers between their ASCII notation and their binary equivalents, not to mention the fact that regular arithmetic instructions are much more convenient to use.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset