Montagem - Procedimentos

Os procedimentos ou sub-rotinas são muito importantes na linguagem assembly, pois os programas em linguagem assembly tendem a ser grandes. Os procedimentos são identificados por um nome. Seguindo este nome, é descrito o corpo do procedimento que realiza um trabalho bem definido. O fim do procedimento é indicado por uma instrução de retorno.

Sintaxe

A seguir está a sintaxe para definir um procedimento -

proc_name:
   procedure body
   ...
   ret

O procedimento é chamado de outra função usando a instrução CALL. A instrução CALL deve ter o nome do procedimento chamado como um argumento conforme mostrado abaixo -

CALL proc_name

O procedimento chamado retorna o controle ao procedimento de chamada usando a instrução RET.

Exemplo

Vamos escrever um procedimento muito simples denominado soma que adiciona as variáveis ​​armazenadas no registro ECX e EDX e retorna a soma no registro EAX -

section	.text
   global _start        ;must be declared for using gcc
	
_start:	                ;tell linker entry point
   mov	ecx,'4'
   sub     ecx, '0'
	
   mov 	edx, '5'
   sub     edx, '0'
	
   call    sum          ;call sum procedure
   mov 	[res], 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, 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
sum:
   mov     eax, ecx
   add     eax, edx
   add     eax, '0'
   ret
	
section .data
msg db "The sum 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 sum is:
9

Estrutura de dados de pilhas

Uma pilha é uma estrutura de dados semelhante a um array na memória, na qual os dados podem ser armazenados e removidos de um local chamado 'topo' da pilha. Os dados que precisam ser armazenados são 'colocados' na pilha e os dados a serem recuperados são 'retirados' da pilha. Stack é uma estrutura de dados LIFO, ou seja, os dados armazenados primeiro são recuperados por último.

A linguagem assembly fornece duas instruções para operações de pilha: PUSH e POP. Essas instruções têm sintaxes como -

PUSH    operand
POP     address/register

O espaço de memória reservado no segmento da pilha é usado para implementar a pilha. Os registros SS e ESP (ou SP) são usados ​​para implementar a pilha. O topo da pilha, que aponta para o último item de dados inserido na pilha, é apontado pelo registro SS: ESP, onde o registro SS aponta para o início do segmento da pilha e o SP (ou ESP) fornece o deslocamento para o segmento da pilha.

A implementação da pilha tem as seguintes características -

  • Somente words ou doublewords pode ser salvo na pilha, não em um byte.

  • A pilha cresce na direção inversa, ou seja, em direção ao endereço de memória inferior

  • O topo da pilha aponta para o último item inserido na pilha; ele aponta para o byte inferior da última palavra inserida.

Conforme discutimos sobre como armazenar os valores dos registradores na pilha antes de usá-los para algum uso; isso pode ser feito da seguinte maneira -

; Save the AX and BX registers in the stack
PUSH    AX
PUSH    BX

; Use the registers for other purpose
MOV	AX, VALUE1
MOV 	BX, VALUE2
...
MOV 	VALUE1, AX
MOV	VALUE2, BX

; Restore the original values
POP	BX
POP	AX

Exemplo

O programa a seguir exibe todo o conjunto de caracteres ASCII. O programa principal chama um procedimento denominado display , que exibe o conjunto de caracteres ASCII.

section	.text
   global _start        ;must be declared for using gcc
	
_start:	                ;tell linker entry point
   call    display
   mov	eax,1	        ;system call number (sys_exit)
   int	0x80	        ;call kernel
	
display:
   mov    ecx, 256
	
next:
   push    ecx
   mov     eax, 4
   mov     ebx, 1
   mov     ecx, achar
   mov     edx, 1
   int     80h
	
   pop     ecx	
   mov	dx, [achar]
   cmp	byte [achar], 0dh
   inc	byte [achar]
   loop    next
   ret
	
section .data
achar db '0'

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}
...
...