Assembly - Istruzioni aritmetiche

L'istruzione INC

L'istruzione INC viene utilizzata per incrementare di uno un operando. Funziona su un singolo operando che può essere in un registro o in memoria.

Sintassi

L'istruzione INC ha la seguente sintassi:

INC destination

La destinazione dell'operando potrebbe essere un operando a 8 bit, 16 bit o 32 bit.

Esempio

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

L'istruzione DEC

L'istruzione DEC viene utilizzata per decrementare un operando di uno. Funziona su un singolo operando che può essere in un registro o in memoria.

Sintassi

L'istruzione DEC ha la seguente sintassi:

DEC destination

La destinazione dell'operando potrebbe essere un operando a 8 bit, 16 bit o 32 bit.

Esempio

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]

Le istruzioni ADD e SUB

Le istruzioni ADD e SUB vengono utilizzate per eseguire semplici addizioni / sottrazioni di dati binari in dimensioni di byte, parola e doppia parola, cioè per aggiungere o sottrarre operandi a 8 bit, 16 bit o 32 bit, rispettivamente.

Sintassi

Le istruzioni ADD e SUB hanno la seguente sintassi:

ADD/SUB	destination, source

L'istruzione ADD / SUB può avvenire tra -

  • Registrati per registrarti
  • Memoria da registrare
  • Registrati in memoria
  • Registrati a dati costanti
  • Memoria a dati costanti

Tuttavia, come altre istruzioni, le operazioni da memoria a memoria non sono possibili utilizzando le istruzioni ADD / SUB. Un'operazione ADD o SUB imposta o cancella i flag di overflow e carry.

Esempio

Il seguente esempio chiederà due cifre all'utente, memorizzerà le cifre rispettivamente nel registro EAX e EBX, aggiungerà i valori, memorizzerà il risultato in una posizione di memoria " res " e infine visualizzerà il risultato.

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

Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:

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

Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:

The sum is:
7

L'istruzione MUL / IMUL

Sono disponibili due istruzioni per moltiplicare i dati binari. L'istruzione MUL (Multiply) gestisce i dati senza segno e l'IMUL (Integer Multiply) gestisce i dati con segno. Entrambe le istruzioni influenzano il flag Carry e Overflow.

Sintassi

La sintassi per le istruzioni MUL / IMUL è la seguente:

MUL/IMUL multiplier

Il moltiplicando in entrambi i casi sarà in un accumulatore, a seconda della dimensione del moltiplicando e del moltiplicatore e anche il prodotto generato viene memorizzato in due registri a seconda della dimensione degli operandi. La sezione seguente spiega le istruzioni MUL con tre diversi casi:

Sr.No. Scenari
1

When two bytes are multiplied −

Il moltiplicando si trova nel registro AL e il moltiplicatore è un byte nella memoria o in un altro registro. Il prodotto è in AX. Gli 8 bit di ordine superiore del prodotto vengono memorizzati in AH e gli 8 bit di ordine inferiore vengono memorizzati in AL.

2

When two one-word values are multiplied −

Il moltiplicando dovrebbe essere nel registro AX e il moltiplicatore è una parola in memoria o un altro registro. Ad esempio, per un'istruzione come MUL DX, è necessario memorizzare il moltiplicatore in DX e il moltiplicando in AX.

Il prodotto risultante è una doppia parola, che richiederà due registri. La parte di ordine superiore (più a sinistra) viene memorizzata in DX e la parte di ordine inferiore (più a destra) viene archiviata in AX.

3

When two doubleword values are multiplied −

Quando due valori di doppia parola vengono moltiplicati, il moltiplicando dovrebbe essere in EAX e il moltiplicatore è un valore di doppia parola archiviato in memoria o in un altro registro. Il prodotto generato viene memorizzato nei registri EDX: EAX, ovvero i 32 bit di ordine alto vengono memorizzati nel registro EDX ei 32 bit di ordine basso vengono memorizzati nel registro EAX.

Esempio

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

Esempio

L'esempio seguente moltiplica 3 per 2 e visualizza il risultato:

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

Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:

The result is:
6

Le istruzioni DIV / IDIV

L'operazione di divisione genera due elementi: a quotient e a remainder. In caso di moltiplicazione, l'overflow non si verifica perché i registri a doppia lunghezza vengono utilizzati per mantenere il prodotto. Tuttavia, in caso di divisione, potrebbe verificarsi un trabocco. Il processore genera un interrupt se si verifica un overflow.

L'istruzione DIV (Divide) viene utilizzata per i dati senza segno e IDIV (Integer Divide) viene utilizzata per i dati con segno.

Sintassi

Il formato per l'istruzione DIV / IDIV -

DIV/IDIV	divisor

Il dividendo è in un accumulatore. Entrambe le istruzioni possono funzionare con operandi a 8 bit, 16 bit o 32 bit. L'operazione influisce su tutti e sei i flag di stato. La sezione seguente spiega tre casi di divisione con diverse dimensioni di operandi:

Sr.No. Scenari
1

When the divisor is 1 byte −

Si presume che il dividendo sia nel registro AX (16 bit). Dopo la divisione, il quoziente va al registro AL e il resto va al registro AH.

2

When the divisor is 1 word −

Si presume che il dividendo sia lungo 32 bit e nei registri DX: AX. I 16 bit di ordine superiore sono in DX e i 16 bit di ordine inferiore sono in AX. Dopo la divisione, il quoziente di 16 bit va al registro AX e il resto di 16 bit va al registro DX.

3

When the divisor is doubleword −

Si presume che il dividendo sia lungo 64 bit e nei registri EDX: EAX. I 32 bit di ordine superiore sono in EDX ei 32 bit di ordine inferiore sono in EAX. Dopo la divisione, il quoziente a 32 bit va al registro EAX e il resto a 32 bit va al registro EDX.

Esempio

L'esempio seguente divide 8 per 2. Il file dividend 8 è memorizzato nel file 16-bit AX register e il divisor 2 è memorizzato nel file 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

Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:

The result is:
4