Zgromadzenie - liczby

Dane liczbowe są zwykle przedstawiane w systemie binarnym. Instrukcje arytmetyczne działają na danych binarnych. Liczby wyświetlane na ekranie lub wprowadzane z klawiatury mają postać ASCII.

Do tej pory przekonwertowaliśmy te dane wejściowe w postaci ASCII na binarne do obliczeń arytmetycznych i przekonwertowaliśmy wynik z powrotem na binarny. Poniższy kod pokazuje to -

section	.text
   global _start        ;must be declared for using gcc
	
_start:	                ;tell linker entry point
   mov	eax,'3'
   sub     eax, '0'
	
   mov 	ebx, '4'
   sub     ebx, '0'
   add 	eax, ebx
   add	eax, '0'
	
   mov 	[sum], eax
   mov	ecx,msg	
   mov	edx, len
   mov	ebx,1	         ;file descriptor (stdout)
   mov	eax,4	         ;system call number (sys_write)
   int	0x80	         ;call kernel
	
   mov	ecx,sum
   mov	edx, 1
   mov	ebx,1	         ;file descriptor (stdout)
   mov	eax,4	         ;system call number (sys_write)
   int	0x80	         ;call kernel
	
   mov	eax,1	         ;system call number (sys_exit)
   int	0x80	         ;call kernel
	
section .data
msg db "The sum is:", 0xA,0xD 
len equ $ - msg   
segment .bss
sum resb 1

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

The sum is:
7

Takie konwersje mają jednak narzut, a programowanie w języku asemblerowym umożliwia bardziej wydajne przetwarzanie liczb w formie binarnej. Liczby dziesiętne można przedstawić w dwóch formach -

  • Formularz ASCII
  • BCD lub postać dziesiętna w kodzie binarnym

Reprezentacja ASCII

W reprezentacji ASCII liczby dziesiętne są przechowywane jako ciąg znaków ASCII. Na przykład wartość dziesiętna 1234 jest przechowywana jako -

31	32	33	34H

Gdzie 31H to wartość ASCII dla 1, 32H to wartość ASCII dla 2 i tak dalej. Istnieją cztery instrukcje przetwarzania liczb w reprezentacji ASCII -

  • AAA - Regulacja ASCII po dodaniu

  • AAS - Regulacja ASCII po odjęciu

  • AAM - Regulacja ASCII po pomnożeniu

  • AAD - Regulacja ASCII przed dzieleniem

Te instrukcje nie pobierają żadnych operandów i zakładają, że wymagany operand znajduje się w rejestrze AL.

W poniższym przykładzie użyto instrukcji AAS, aby zademonstrować koncepcję -

section	.text
   global _start        ;must be declared for using gcc
	
_start:	                ;tell linker entry point
   sub     ah, ah
   mov     al, '9'
   sub     al, '3'
   aas
   or      al, 30h
   mov     [res], ax
	
   mov	edx,len	        ;message length
   mov	ecx,msg	        ;message to write
   mov	ebx,1	        ;file descriptor (stdout)
   mov	eax,4	        ;system call number (sys_write)
   int	0x80	        ;call kernel
	
   mov	edx,1	        ;message length
   mov	ecx,res	        ;message to write
   mov	ebx,1	        ;file descriptor (stdout)
   mov	eax,4	        ;system call number (sys_write)
   int	0x80	        ;call kernel
	
   mov	eax,1	        ;system call number (sys_exit)
   int	0x80	        ;call kernel
	
section	.data
msg db 'The Result is:',0xa	
len equ $ - msg			
section .bss
res resb 1

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

The Result is:
6

Reprezentacja BCD

Istnieją dwa rodzaje reprezentacji BCD -

  • Rozpakowana reprezentacja BCD
  • Zapakowana reprezentacja BCD

W rozpakowanej reprezentacji BCD każdy bajt przechowuje binarny odpowiednik cyfry dziesiętnej. Na przykład liczba 1234 jest przechowywana jako -

01	02	03	04H

Istnieją dwie instrukcje dotyczące przetwarzania tych liczb -

  • AAM - Regulacja ASCII po pomnożeniu

  • AAD - Regulacja ASCII przed dzieleniem

Cztery instrukcje ASCII, AAA, AAS, AAM i AAD, mogą być również używane z rozpakowaną reprezentacją BCD. W spakowanej reprezentacji BCD każda cyfra jest przechowywana przy użyciu czterech bitów. Dwie cyfry dziesiętne są umieszczane w bajcie. Na przykład liczba 1234 jest przechowywana jako -

12	34H

Istnieją dwie instrukcje dotyczące przetwarzania tych liczb -

  • DAA - Korekta dziesiętna po dodaniu

  • DAS - Regulacja dziesiętna po odjęciu

Nie ma obsługi mnożenia i dzielenia w spakowanej reprezentacji BCD.

Przykład

Poniższy program dodaje dwie 5-cyfrowe liczby dziesiętne i wyświetla sumę. Wykorzystuje powyższe koncepcje -

section	.text
   global _start        ;must be declared for using gcc

_start:	                ;tell linker entry point

   mov     esi, 4       ;pointing to the rightmost digit
   mov     ecx, 5       ;num of digits
   clc
add_loop:  
   mov 	al, [num1 + esi]
   adc 	al, [num2 + esi]
   aaa
   pushf
   or 	al, 30h
   popf
	
   mov	[sum + esi], al
   dec	esi
   loop	add_loop
	
   mov	edx,len	        ;message length
   mov	ecx,msg	        ;message to write
   mov	ebx,1	        ;file descriptor (stdout)
   mov	eax,4	        ;system call number (sys_write)
   int	0x80	        ;call kernel
	
   mov	edx,5	        ;message length
   mov	ecx,sum	        ;message to write
   mov	ebx,1	        ;file descriptor (stdout)
   mov	eax,4	        ;system call number (sys_write)
   int	0x80	        ;call kernel
	
   mov	eax,1	        ;system call number (sys_exit)
   int	0x80	        ;call kernel

section	.data
msg db 'The Sum is:',0xa	
len equ $ - msg			
num1 db '12345'
num2 db '23456'
sum db '     '

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

The Sum is:
35801