Assemblaggio - Procedure

Le procedure o le subroutine sono molto importanti nel linguaggio assembly, poiché i programmi in linguaggio assembly tendono ad essere di grandi dimensioni. Le procedure sono identificate da un nome. Dopo questo nome, viene descritto il corpo della procedura che esegue un lavoro ben definito. La fine della procedura è indicata da una dichiarazione di reso.

Sintassi

Di seguito è riportata la sintassi per definire una procedura:

proc_name:
   procedure body
   ...
   ret

La procedura viene chiamata da un'altra funzione utilizzando l'istruzione CALL. L'istruzione CALL dovrebbe avere il nome della procedura chiamata come argomento come mostrato di seguito -

CALL proc_name

La procedura chiamata restituisce il controllo alla procedura chiamante utilizzando l'istruzione RET.

Esempio

Scriviamo una procedura molto semplice denominata sum che aggiunge le variabili memorizzate nel registro ECX ed EDX e restituisce la somma nel 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 il codice precedente viene compilato ed eseguito, produce il seguente risultato:

The sum is:
9

Stack struttura dati

Uno stack è una struttura di dati simile a un array nella memoria in cui i dati possono essere archiviati e rimossi da una posizione denominata "cima" dello stack. I dati che devono essere archiviati vengono "inseriti" nello stack ei dati da recuperare vengono "estratti" dallo stack. Lo stack è una struttura dati LIFO, ovvero i dati memorizzati per primi vengono recuperati per ultimi.

Il linguaggio Assembly fornisce due istruzioni per le operazioni sullo stack: PUSH e POP. Queste istruzioni hanno sintassi come -

PUSH    operand
POP     address/register

Lo spazio di memoria riservato nel segmento dello stack viene utilizzato per l'implementazione dello stack. I registri SS e ESP (o SP) vengono utilizzati per implementare lo stack. La parte superiore della pila, che punta all'ultimo elemento di dati inserito nella pila, è indicata dal registro SS: ESP, dove il registro SS punta all'inizio del segmento dello stack e SP (o ESP) fornisce l'offset in il segmento dello stack.

L'implementazione dello stack ha le seguenti caratteristiche:

  • Solo words o doublewords potrebbe essere salvato nello stack, non in un byte.

  • Lo stack cresce nella direzione opposta, cioè verso l'indirizzo di memoria inferiore

  • La parte superiore della pila punta all'ultimo elemento inserito nella pila; punta al byte inferiore dell'ultima parola inserita.

Come abbiamo discusso sulla memorizzazione dei valori dei registri nello stack prima di usarli per qualche uso; può essere fatto in questo modo:

; 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

Esempio

Il seguente programma visualizza l'intero set di caratteri ASCII. Il programma principale chiama una procedura denominata display , che visualizza il set di caratteri 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 il codice precedente viene compilato ed eseguito, produce il seguente risultato:

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