Variabili in Assembly

Da Hacknowledge.

In Assembly una variabile non è altro che un'allocazione di spazio identificata da un etichetta e un tipo, che può essere fatta in qualsiasi parte del programma. La sintassi della dichiarazione è questa:

nome:   .tipo   valore

Esempio:

hello:  .string  "Ciao\n"

Dichiara una stringa chiamata hello e contenente i valori ASCII che formano la parola "Ciao\n". Una dichiarazione può essere fatta in qualsiasi punto del codice, anche se per maggior pulizia del codice è consigliato dichiarare le variabili nel segmento dati dell'applicazione. Il tipo .string è stato già incontrato nell'esempio precedente, e identifica una normale stringa ASCII. Fra gli altri tipi:

.byte      # Singolo byte o carattere
.word      # short int, 2 byte
.long      # long int, 4 byte
.string    # stringhe
.space     # allocazione di spazio arbitrario

Il tipo .space è molto particolare. È più o meno corrispondente al tipo void di linguaggi come il C, identifica semplicemente uno spazio di dimensione arbitraria da allocare in memoria,e torna utile per definire tutti i tipi di dati derivati (strutture, enumerazioni ecc.). Esempio:

# Alloco una variabile grande 64 byte
var:   .space   64

Indice

[modifica] Costanti

Le costanti in sintassi AT&T si dichiarano semplicemente nel seguente modo

nome = valore

Esempio:

var = 2

[modifica] Dimensione di una variabile

La sintassi AT&T mette a disposizione un modo estremamente versatile e veloce per conoscere la dimensione di una variabile o la lunghezza di una stringa. Ecco la sintassi:

str:   .string   "Ciao\n"
str_len = .-str

A questo punto la variabile str_len conterrà la lunghezza della variabile str. Si può ovviamente applicare a tutti i tipi di dato:

myspace:   .space   64
myspace_size = .-myspace    # myspace_size=64

[modifica] Passaggi per valore e per riferimento

Facendo precedere al nome di una variabile il simbolo $ si identifica il suo indirizzo, a meno che essa non sia una costante (in questo caso il simbolo $ è obbligatorio). L'abbiamo visto anche nell'esempio precedente per quanto riguarda la scrittura su stdout di una stringa. La syscall write prende come argomento l'indirizzo della zona di memoria da scrivere, e in quel caso facevamo precedere la nostra stringa dal simbolo $. Quando invece vogliamo identificare il valore contenuto in una variabile e non il suo indirizzo useremo semplicemente il nome della variabile senza prefissi, oppure il nome della variabile fra parentesi (le due notazioni sono equivalenti). Ovviamente questo ragionamento non è applicabile alle stringhe, che sono sempre viste come puntatori a zone di memoria terminanti con \0. Esempio:

.data
var:            .long   4
 
.text
        .global main
main:
        movl            $var,%eax
        movl            var,%ebx
 
......

Andando a debuggare vedremmo

10              movl            $var,%eax
Current language:  auto; currently asm
(gdb) p/x $eax
$1 = 0x80495d8    # Indirizzo di var
...
11              movl            var,%ebx
(gdb) p $ebx
$2 = 4      # Contenuto di var

[modifica] Esempio di read

Con le nozioni che abbiamo ora, vediamo come poter leggere una stringa da stdin e stamparla nuovamente su stdout:

.data
# Alloco lo spazio per la stringa str
str:            .space  128
 
# Lunghezza della stringa
str_len =       .-str
 
.text
        .global main
main:
        # Chiamata a sys_read - funzione 3 dell interrupt 0x80
        movl            $3,%eax
 
        # Primo argomento della funzione 0 -> stdin
        movl            $0,%ebx
 
        # Passo l indirizzo della stringa e la relativa lunghezza
        movl            $str,%ecx
        movl            $str_len,%edx
        int             $0x80
 
        # Stampo la stringa letta
        movl            $4,%eax
        movl            $1,%ebx
        movl            $str,%ecx
        movl            $str_len,%edx
        int             $0x80
 
        movl            $1,%eax
        movl            $0,%ebx
        int             $0x80
 
        leave
        ret

[modifica] Valori di ritorno

I valori di ritorno di una syscall vanno generalmente piazzati in EAX. Esempio, la syscall read ritorna il numero di byte letti dal descrittore, e tale valore è leggibile in EAX:

.data
# Alloco lo spazio per la stringa str
str:            .space  128
 
# Lunghezza della stringa
str_len =       .-str
 
# Numero di caratteri letti
N               .long   0
 
.text
        .global main
main:
        movl            $3,%eax
        movl            $0,%ebx
        movl            $str,%ecx
        movl            $str_len,%edx
        int             $0x80
        movl            %eax,N    # N ora conterrà il valore di ritorno della chiamata, ovvero il numero di byte letti
Strumenti personali