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

