汇编语言AAA指令多字节加法代码分析(5)

 

来自于《Intel汇编语言程序设计》(第五版)第七章的代码,使用AAA( ASCII adjust after addition )指令来调整ASCII相加之后的结果。源代码如下:

 

TITLE ASCII Addition                                                    (ASCII_add.asm)

 

; Perform ASCII arithmetic on strings having

; an implied fixed decimal point

 

INCLUDE Irvine32.inc

 

DECIMAL_OFFSET = 5                                                 ; offset from right of string

 

.data

decimal_one BYTE "100123456789765"                     ; 1001234567.89765

decimal_two BYTE "900402076502015"                     ; 9004020765.02015

sum BYTE (SIZEOF decimal_one + 1) DUP(0),0

 

.code

main PROC

; start at the last digit position.

           mov esi, SIZEOF decimal_one - 1

           mov edi,SIZEOF decimal_one

           mov ecx,SIZEOF decimal_one

           mov bh,0                                                          ; set carry value to zero

L1:

           mov ah,0                                                          ; clear AH before addition

           mov al,decimal_one[esi]                                   ; get the first digit

           add al,bh                                                          ; add the previous carry

           aaa                                                                   ; adjust the sum ( AH = carry )

           mov bh,ah                                                         ; save the carry in carry1

           or bh,30h                                                          ; convert it to ASCII

           add al,decimal_two[esi]                                   ; add the second digit

           aaa                                                                   ; adjust the sum ( AH = carry )

           or bh,ah                                                           ; OR the carry with carry1

           or bh,30h                                                          ; convert it to ASCII

           or al,30h                                                           ; convert AL back to ASCII

           mov sum[edi],al                                                ; save it in the sum

           dec esi                                                              ; back up one digit

           dec edi

           loop L1

           mov sum[edi],bh;                                             ; save last carry digit

; Display the sum as a string.

           mov edx,OFFSET sum

           call WriteString

           call crlf

           exit

main ENDP

END main

 

 

下面开始逐句分析。

 

 

decimal_one BYTE "100123456789765"                     ; 1001234567.89765

decimal_one BYTE "900402076502015"                     ; 9004020765.02015

sum BYTE (SIZEOF decimal_one + 1) DUP(0),0

 

首先定义了两个数字字符串,用来隐含进行小数点的加法。随后定义了一个放置和的sum变量,这个变量多了一位来放置进位。

 

 

然后再来看代码段:

 

 

           mov esi, SIZEOF decimal_one - 1

           mov edi,SIZEOF decimal_one

           mov ecx,SIZEOF decimal_one

           mov bh,0                                                          ; set carry value to zero

 

首先,为循环游标 esi 赋值为字符串的最后一个位置,即SIZEOF decimal_one - 1,此时即指向decimal_one的最后一位数字"5" 。 然后是sum的游标edi,为其赋值为SIZEOF decimal_one(因为我们这里比decimal_one的长度多了一位,用来存储进位),还有循环数ecx,赋值为decimal_one的长度。

 

最后把进位值bh设置为零。

 

 

 

然后让我们看一下接下来的代码:

 

 

 

L1:

           mov ah,0                                                          ; 在进行AAA指令之前,一定要清空ah,否则会影响AAA指令结果

           mov al,decimal_one[esi]                                   ; 得到decimal_one的esi位置的数字

           add al,bh                                                          ; 将之前的进位值与al相加(例如,第一次相加时没有进位)

           aaa                                                                   ; 使用aaa调整相加结果,会将进位值保存到ah中

           mov bh,ah                                                         ; 将进位值保存到bh中

           or bh,30h                                                          ; 将此时的结果转化成ASCII码

           add al,decimal_two[esi]                                   ; 再与decimal_two的第esi位数字相加,保存到al中

           aaa                                                                   ; 调整加法结果,进位将会保存到AH中

           or bh,ah                                                           ; 将现在的进位进行或操作(不太明白为什么)

           or bh,30h                                                          ; 将进位值转化为ASCII码

           or al,30h                                                           ; 将AL中的值转化为ASCII码

           mov sum[edi],al                                                ; 将计算完的此位值赋值到sum相应位

           dec esi                                                              ; 向前移一位,取得下一个相加数的游标位置

           dec edi                                                              ; 向前移一位,取得下一个相加数的游标位置

           loop L1                                                              ; 执行下次循环

           mov sum[edi],bh;                                             ; 计算完成之后,将最后一次的进位加到sum的第edi位置

 

; Display the sum as a string.

           mov edx,OFFSET sum                                       ; 将sum的偏移地址赋值到edx中

           call WriteString                                                 ; 在屏幕上显示此时edx的值,也就是sum的结果

           call crlf                                                              ; 光标移动到下一行开头

           exit                                                                   ; 退出(Irvine32中的函数)

 

 

到这里,程序分析便结束了,程序的结果将为:

 

1000525533291780

 

结果共为16位(原两个相加数为15位),并且隐含了小数点。

 

 

补充:

因为 ASCII 码的十进制数中的最高位总是0011b,所以才会进行 or bh,30h 的操作;其中未将ASCII码的十进制数的高四位设置为0011b的为未压缩格式,设置之后的才为ASCII格式,示例如下:

 

ASCII格式:    33 34 30 32

未压缩格式:    03 04 00 02

 

 

你可能感兴趣的:(UP)