aaa(ASCII adjust after addition)指令,是BCD指令集中的一个指令,用于在两个未打包的BCD值相加后,调整al和ah寄存器的内容。
BCD(Binary-coded decimal)数是指2进制编码的10进制数,占据一个字节的低4位,只有0-9是有效值。
AAA指令做两件事情:
如果al的低4位是在0到9之间,保留低4位,清除高4位,如果al的低4位在10到15之间,则通过加6,来使得低4位在0到9之间,然后再对高4位清零。
如果al的低4位是在0到9之间,ah值不变,CF和AF标志清零,否则,ah=ah+1,并设置CF和AF标志。
下面看一个示例程序:
section .data
EditBuff: db 'abcdefghijklm',10
BUFFERLEN equ $-EditBuff
FILLCHR equ 35 ;'#'
section .text
WriteStr:
push eax ; Save pertinent registers
push ebx
mov eax,4 ; Specify sys_write call
mov ebx,1 ; Specify File Descriptor 1: Stdout
int 80H ; Make the kernel call
pop ebx ; Restore pertinent registers
pop eax
ret ; Go home
global _start
_start:
nop
mov ecx,EditBuff
mov edx,BUFFERLEN
call WriteStr
mov edi,EditBuff
mov ecx,BUFFERLEN-1
mov al,'1' ; Start ruler with digit '1'
DoChar: stosb ; Note that there's no REP prefix!
add al,'1' ; Bump the character value in AL up by 1
aaa ; Adjust AX to make this a BCD addition
add al,'0' ; Make sure we have binary 3 in AL's high nybble
loop DoChar ; Go back & do another char until ECX goes to 0
mov ecx,EditBuff
mov edx,BUFFERLEN
call WriteStr
Exit: mov eax,1 ; Code for Exit Syscall
mov ebx,0 ; Return a code of zero
int 80H ; Make kernel call
程序分析:
mov edi,EditBuff //edi = EditBuff
mov ecx,BUFFERLEN-1 //ecx= BUFFERLEN-1,这样可以不覆盖最后一个换行符
mov al,'1' //al = ‘1’,1的ASCII码值是0x31,低4位恰好是有效的BCD值
DoChar: stosb //edi=al
add al,'1' //两个ASCII码值相加。
aaa //使用aaa指令进行调整,使得低4位是有效的BCD值。只有’9’加’1’会形成无效BCD数(10),调整后al会等于0,其他都不需要调整低4位,只是简单对高4位清零。
add al,'0' //要把数字转换成ASCII码,需要再把’0’加回来,例如9+’0’=’9’。
loop DoChar //ecx=ecx-1,如果ecx不等于0,跳转到DoChar继续循环。ecx=13,所以会填充字符13次。
makefile文件内容:
aaademo: aaademo.o
ld -o aaademo aaademo.o
aaademo.o: aaademo.asm
nasm -f elf -g -F stabs aaademo.asm -l aaademo.lst
测试:
[root@bogon aaademo]# make
nasm -f elf -g -F stabs aaademo.asm -l aaademo.lst
ld -o aaademo aaademo.o
[root@bogon aaademo]# ./aaademo
abcdefghijklm
1234567890123