Montaż - instrukcje arytmetyczne

Instrukcja INC

Instrukcja INC jest używana do zwiększania operandu o jeden. Działa na pojedynczym operandzie, który może znajdować się w rejestrze lub w pamięci.

Składnia

Instrukcja INC ma następującą składnię -

INC destination

Miejsce docelowe operandu może być 8-bitowym, 16-bitowym lub 32-bitowym operandem.

Przykład

INC EBX	     ; Increments 32-bit register
INC DL       ; Increments 8-bit register
INC [count]  ; Increments the count variable

Instrukcja DEC

Instrukcja DEC służy do zmniejszania wartości operandu o jeden. Działa na pojedynczym operandzie, który może znajdować się w rejestrze lub w pamięci.

Składnia

Instrukcja DEC ma następującą składnię -

DEC destination

Miejsce docelowe operandu może być 8-bitowym, 16-bitowym lub 32-bitowym operandem.

Przykład

segment .data
   count dw  0
   value db  15
	
segment .text
   inc [count]
   dec [value]
	
   mov ebx, count
   inc word [ebx]
	
   mov esi, value
   dec byte [esi]

Instrukcje ADD i SUB

Instrukcje ADD i SUB są używane do wykonywania prostego dodawania / odejmowania danych binarnych w rozmiarze bajtu, słowa i słowa podwójnego, tj. Do dodawania lub odejmowania odpowiednio 8-bitowych, 16-bitowych lub 32-bitowych argumentów.

Składnia

Instrukcje ADD i SUB mają następującą składnię -

ADD/SUB	destination, source

Instrukcja ADD / SUB może mieć miejsce między -

  • Zarejestruj się, aby się zarejestrować
  • Pamięć do zarejestrowania
  • Zarejestruj się w pamięci
  • Zarejestruj się na stałe dane
  • Pamięć do stałych danych

Jednak, podobnie jak inne instrukcje, operacje z pamięci do pamięci nie są możliwe przy użyciu instrukcji ADD / SUB. Operacja ADD lub SUB ustawia lub usuwa przepełnienie i flagi przenoszenia.

Przykład

Poniższy przykład poprosi użytkownika o podanie dwóch cyfr, zapisze cyfry odpowiednio w rejestrze EAX i EBX, doda wartości, zapisze wynik w lokalizacji pamięci „ res ” i ostatecznie wyświetli wynik.

SYS_EXIT  equ 1
SYS_READ  equ 3
SYS_WRITE equ 4
STDIN     equ 0
STDOUT    equ 1

segment .data 

   msg1 db "Enter a digit ", 0xA,0xD 
   len1 equ $- msg1 

   msg2 db "Please enter a second digit", 0xA,0xD 
   len2 equ $- msg2 

   msg3 db "The sum is: "
   len3 equ $- msg3

segment .bss

   num1 resb 2 
   num2 resb 2 
   res resb 1    

section	.text
   global _start    ;must be declared for using gcc
	
_start:             ;tell linker entry point
   mov eax, SYS_WRITE         
   mov ebx, STDOUT         
   mov ecx, msg1         
   mov edx, len1 
   int 0x80                

   mov eax, SYS_READ 
   mov ebx, STDIN  
   mov ecx, num1 
   mov edx, 2
   int 0x80            

   mov eax, SYS_WRITE        
   mov ebx, STDOUT         
   mov ecx, msg2          
   mov edx, len2         
   int 0x80

   mov eax, SYS_READ  
   mov ebx, STDIN  
   mov ecx, num2 
   mov edx, 2
   int 0x80        

   mov eax, SYS_WRITE         
   mov ebx, STDOUT         
   mov ecx, msg3          
   mov edx, len3         
   int 0x80

   ; moving the first number to eax register and second number to ebx
   ; and subtracting ascii '0' to convert it into a decimal number
	
   mov eax, [num1]
   sub eax, '0'
	
   mov ebx, [num2]
   sub ebx, '0'

   ; add eax and ebx
   add eax, ebx
   ; add '0' to to convert the sum from decimal to ASCII
   add eax, '0'

   ; storing the sum in memory location res
   mov [res], eax

   ; print the sum 
   mov eax, SYS_WRITE        
   mov ebx, STDOUT
   mov ecx, res         
   mov edx, 1        
   int 0x80

exit:    
   
   mov eax, SYS_EXIT   
   xor ebx, ebx 
   int 0x80

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

Enter a digit:
3
Please enter a second digit:
4
The sum is:
7

The program with hardcoded variables −

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

Instrukcja MUL / IMUL

Istnieją dwie instrukcje dotyczące mnożenia danych binarnych. Instrukcja MUL (Multiply) obsługuje dane bez znaku, a IMUL (Integer Multiply) obsługuje dane ze znakiem. Obie instrukcje mają wpływ na flagę Carry i Overflow.

Składnia

Składnia instrukcji MUL / IMUL jest następująca -

MUL/IMUL multiplier

Mnożnik w obu przypadkach będzie w akumulatorze, w zależności od rozmiaru mnożnika i mnożnika, a wygenerowany iloczyn jest również przechowywany w dwóch rejestrach w zależności od rozmiaru argumentów. Poniższa sekcja wyjaśnia instrukcje MUL w trzech różnych przypadkach -

Sr.No. Scenariusze
1

When two bytes are multiplied −

Mnożnik znajduje się w rejestrze AL, a mnożnik jest bajtem w pamięci lub w innym rejestrze. Produkt jest w AX. 8 bitów produktu wysokiego rzędu jest przechowywanych w AH, a 8 bitów niskiego rzędu jest przechowywanych w AL.

2

When two one-word values are multiplied −

Mnożnik powinien znajdować się w rejestrze AX, a mnożnik to słowo w pamięci lub inny rejestr. Na przykład, dla instrukcji takiej jak MUL DX, musisz zapisać mnożnik w DX, a mnożnik w AX.

Otrzymany iloczyn jest podwójnym słowem, które będzie wymagało dwóch rejestrów. Część najwyższego rzędu (skrajna lewa) jest przechowywana w DX, a część niższego rzędu (skrajna prawa) jest przechowywana w AX.

3

When two doubleword values are multiplied −

Kiedy mnoży się dwie wartości podwójnego słowa, mnożnik powinien być w EAX, a mnożnik jest wartością podwójnego słowa przechowywaną w pamięci lub w innym rejestrze. Wygenerowany produkt jest przechowywany w rejestrach EDX: EAX, tj. 32 bity wyższego rzędu są zapisywane w rejestrze EDX, a 32 bity najniższego rzędu są przechowywane w rejestrze EAX.

Przykład

MOV AL, 10
MOV DL, 25
MUL DL
...
MOV DL, 0FFH	; DL= -1
MOV AL, 0BEH	; AL = -66
IMUL DL

Przykład

Poniższy przykład mnoży 3 przez 2 i wyświetla wynik -

section	.text
   global _start    ;must be declared for using gcc
	
_start:             ;tell linker entry point

   mov	al,'3'
   sub     al, '0'
	
   mov 	bl, '2'
   sub     bl, '0'
   mul 	bl
   add	al, '0'
	
   mov 	[res], al
   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,res
   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 result is:", 0xA,0xD 
len equ $- msg   
segment .bss
res resb 1

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

The result is:
6

Instrukcje DIV / IDIV

Operacja dzielenia generuje dwa elementy - a quotient i a remainder. W przypadku mnożenia przepełnienie nie występuje, ponieważ do przechowywania iloczynu używane są rejestry o podwójnej długości. Jednak w przypadku podziału może wystąpić przelanie. Procesor generuje przerwanie, jeśli wystąpi przepełnienie.

Instrukcja DIV (Divide) jest używana dla danych bez znaku, a IDIV (Integer Divide) jest używana dla danych ze znakiem.

Składnia

Format instrukcji DIV / IDIV -

DIV/IDIV	divisor

Dywidenda jest akumulowana. Obie instrukcje mogą działać z 8-bitowymi, 16-bitowymi lub 32-bitowymi operandami. Operacja wpływa na wszystkie sześć flag stanu. Poniższa sekcja wyjaśnia trzy przypadki dzielenia z różnymi rozmiarami operandów -

Sr.No. Scenariusze
1

When the divisor is 1 byte −

Zakłada się, że dywidenda znajduje się w rejestrze AX (16 bitów). Po podzieleniu iloraz trafia do rejestru AL, a reszta do rejestru AH.

2

When the divisor is 1 word −

Zakłada się, że dywidenda ma długość 32 bity i znajduje się w rejestrach DX: AX. 16 bitów wysokiego rzędu jest w DX, a 16 bitów niskiego rzędu w AX. Po podzieleniu, 16-bitowy iloraz trafia do rejestru AX, a 16-bitowa reszta trafia do rejestru DX.

3

When the divisor is doubleword −

Zakłada się, że dywidenda ma długość 64 bitów i jest zapisana w rejestrach EDX: EAX. 32 bity najwyższego rzędu są w EDX, a 32 bity najniższego rzędu w EAX. Po podzieleniu 32-bitowy iloraz trafia do rejestru EAX, a 32-bitowa reszta trafia do rejestru EDX.

Przykład

Poniższy przykład dzieli 8 przez 2. dividend 8 jest przechowywany w 16-bit AX register i divisor 2 jest przechowywany w 8-bit BL register.

section	.text
   global _start    ;must be declared for using gcc
	
_start:             ;tell linker entry point
   mov	ax,'8'
   sub     ax, '0'
	
   mov 	bl, '2'
   sub     bl, '0'
   div 	bl
   add	ax, '0'
	
   mov 	[res], ax
   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,res
   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 result is:", 0xA,0xD 
len equ $- msg   
segment .bss
res resb 1

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

The result is:
4