Montagem - instruções aritméticas

A Instrução INC

A instrução INC é usada para incrementar um operando em um. Ele funciona em um único operando que pode estar em um registro ou na memória.

Sintaxe

A instrução INC tem a seguinte sintaxe -

INC destination

O destino do operando pode ser um operando de 8, 16 ou 32 bits.

Exemplo

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

A Instrução DEC

A instrução DEC é usada para diminuir um operando em um. Ele funciona em um único operando que pode estar em um registro ou na memória.

Sintaxe

A instrução DEC tem a seguinte sintaxe -

DEC destination

O destino do operando pode ser um operando de 8, 16 ou 32 bits.

Exemplo

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]

As instruções ADD e SUB

As instruções ADD e SUB são usadas para realizar adição / subtração simples de dados binários em tamanho de byte, palavra e palavra dupla, ou seja, para adicionar ou subtrair operandos de 8, 16 ou 32 bits, respectivamente.

Sintaxe

As instruções ADD e SUB têm a seguinte sintaxe -

ADD/SUB	destination, source

A instrução ADD / SUB pode ocorrer entre -

  • Cadastre-se para se registrar
  • Memória para registrar
  • Registre-se na memória
  • Registre-se para dados constantes
  • Memória para dados constantes

No entanto, como outras instruções, as operações de memória para memória não são possíveis usando as instruções ADD / SUB. Uma operação ADD ou SUB define ou limpa os sinalizadores de overflow e carry.

Exemplo

O exemplo a seguir pedirá dois dígitos ao usuário, armazenará os dígitos no registrador EAX e EBX, respectivamente, adicionará os valores, armazenará o resultado em um local de memória ' res ' e finalmente exibirá o resultado.

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 o código acima é compilado e executado, ele produz o seguinte resultado -

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 o código acima é compilado e executado, ele produz o seguinte resultado -

The sum is:
7

A Instrução MUL / IMUL

Existem duas instruções para multiplicar dados binários. A instrução MUL (Multiply) lida com dados não assinados e o IMUL (Integer Multiply) lida com dados assinados. Ambas as instruções afetam o sinalizador Carry e Overflow.

Sintaxe

A sintaxe para as instruções MUL / IMUL é a seguinte -

MUL/IMUL multiplier

Multiplicando em ambos os casos estará em um acumulador, dependendo do tamanho do multiplicando e do multiplicador e o produto gerado também é armazenado em dois registradores dependendo do tamanho dos operandos. A seção a seguir explica as instruções do MUL com três casos diferentes -

Sr. Não. Cenários
1

When two bytes are multiplied −

O multiplicando está no registrador AL, e o multiplicador é um byte na memória ou em outro registrador. O produto está em AX. Os 8 bits de ordem superior do produto são armazenados em AH e os 8 bits de ordem inferior são armazenados em AL.

2

When two one-word values are multiplied −

O multiplicando deve estar no registrador AX, e o multiplicador é uma palavra na memória ou outro registrador. Por exemplo, para uma instrução como MUL DX, você deve armazenar o multiplicador em DX e o multiplicando em AX.

O produto resultante é uma palavra dupla, que precisará de dois registros. A parte de ordem superior (extrema esquerda) é armazenada em DX e a parte de ordem inferior (extrema direita) é armazenada em AX.

3

When two doubleword values are multiplied −

Quando dois valores de palavra dupla são multiplicados, o multiplicando deve estar em EAX e o multiplicador é um valor de palavra dupla armazenado na memória ou em outro registro. O produto gerado é armazenado nos registradores EDX: EAX, ou seja, os 32 bits de ordem superior são armazenados no registrador EDX e os 32 bits de ordem inferior são armazenados no registrador EAX.

Exemplo

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

Exemplo

O exemplo a seguir multiplica 3 por 2 e exibe o resultado -

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 o código acima é compilado e executado, ele produz o seguinte resultado -

The result is:
6

As instruções DIV / IDIV

A operação de divisão gera dois elementos - um quotient e um remainder. No caso de multiplicação, o estouro não ocorre porque registros de comprimento duplo são usados ​​para manter o produto. No entanto, em caso de divisão, pode ocorrer estouro. O processador gera uma interrupção se ocorrer estouro.

A instrução DIV (Divide) é usada para dados sem sinal e o IDIV (Integer Divide) é usado para dados assinados.

Sintaxe

O formato da instrução DIV / IDIV -

DIV/IDIV	divisor

O dividendo está em um acumulador. Ambas as instruções podem funcionar com operandos de 8, 16 ou 32 bits. A operação afeta todos os seis sinalizadores de status. A seção a seguir explica três casos de divisão com diferentes tamanhos de operando -

Sr. Não. Cenários
1

When the divisor is 1 byte −

O dividendo é assumido como estando no registrador AX (16 bits). Após a divisão, o quociente vai para o registrador AL e o restante vai para o registrador AH.

2

When the divisor is 1 word −

O dividendo é assumido como tendo 32 bits de comprimento e nos registradores DX: AX. Os 16 bits de ordem superior estão em DX e os 16 bits de ordem inferior estão em AX. Após a divisão, o quociente de 16 bits vai para o registrador AX e o restante de 16 bits vai para o registrador DX.

3

When the divisor is doubleword −

O dividendo é assumido como tendo 64 bits de comprimento e nos registradores EDX: EAX. Os 32 bits de ordem superior estão em EDX e os 32 bits de ordem inferior estão em EAX. Após a divisão, o quociente de 32 bits vai para o registrador EAX e o restante de 32 bits vai para o registrador EDX.

Exemplo

O exemplo a seguir divide 8 por 2. O dividend 8 é armazenado no 16-bit AX register e a divisor 2 é armazenado no 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 o código acima é compilado e executado, ele produz o seguinte resultado -

The result is:
4