您的位置:首页 > 编程语言

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

2009-10-21 10:49 423 查看
来自于《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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息