Linguaggio assembly è una forma leggibile dall’uomo del linguaggio nativo del calcolatore (linguaggio macchina); questo è formato da un insieme di 0 e 1 e viene eseguito dai processori per fare delle operazioni. Ogni architettura è definita in termini di set di istruzioni e di locazione degli operandi, noi ci concentriamo su ARMv7 (32 bit a parola).
I set di architetture, sono dialetti piuttosto che linguaggi, infatti ogni processore ha il proprio, ma tutti implementano alcune operazioni base (addiziona, sottrai, salta)
L’organizzazione dei registri, processore, memoria e ALU è chiamata micro-architettura.
Gli operandi associano ad ogni “nome di variabile", una locazione fisica da cui prelevare i dati binari, che rappresentano il valore:
#costante
- Numero costante; può essere anche un numero in un altra rappresentazione. Per i numeri esadecimali mettiamo prima #0x
.
R0,…R12
- Registri utili, ovvero locazioni fisiche raggiungibili più facilmente e non salvate in memoria (ciò che viene salvato in memoria è più lento da raggiungere)
R0
- Utilizzato per parametro/ valore di ritorno funzione / variabile temporaneaR1…R3
- Utilizzato per parametri / variabili temporaneeR4…R11
R12
- Utilizzato per variabile temporaneaR13
(SP) - Stack pointer
R14
(LR) - Link register
R15
(PC) - Program counter
I registri sono pochi per i dati di un programma intero, si usa una memoria di lavoro:
E’ organizzata come un vettore di parole
Ogni byte di memoria ha un’indirizzo univoco (32 bit indirizzi e 32 bit parole)
Una parola da 32 bit, è formata da 4 byte da 8 bit ciascuno. ogni indirizzo di memoria è un multiplo da 4 byte (posizioni)
Il byte più significativo MSB e il meno significativo LSB, si trovano agli estremi:
Per gestire la memoria (stack) ARM mette a disposizioni due operazioni LDR e STR:
LDR (LoaD Register) ⇒ carica il contenuto di una locazione specifica di memoria
LDR R_dest, [registro, #offset]
Lo spiazzamento (offset), può essere rappresentato da un’immediato o un registro. Nel caso di un registro, il valore di offset è dato dal valore contenuto in esso.
Per il suo calcolo, possono essere usati il post-incremento e il pre-incremento:
LDR R_dest, [registro], valore
LDR R_dest, [registro, valore]!
LDRB → legge solo 1 byte dalla memoria
STR (STore Register) ⇒ memorizza il contenuto di un registro in una locazione di memoria
STR R_source, [R_dest, #offset]
L’indirizzo di memoria viene specificato da un registro base (destinazione) e un’offest.
Come per il LDR è possibile il post e pre incremento:
STR registro1, [registro2], valore
STR registro1, [registro2, valore]!
STRB → memorizza solo 1 byte del registro sorgente, nell’allocazione specificata
Invece di utilizzare una word intera, tutti i numeri compresi tra [-128, 127] possono essere contenuti in 1 byte, grazie alla codifica ASCII.
Per gestire la notazione esadecimale, e quindi le stringhe. si utilizzano le istruzioni per singoli byte in memoria:
LDRB
⇒ carica il byte in indirizzo 2 nella meno significativaLDRSB
⇒ carica il byte in indirizzo 2 nella meno signficativa, mantendo il segnoSTRB
⇒ memorizza il byte LSB del registro nel byte di indirizzo 3 in memoria@
è il simbolo per il commento
MOV R_dest, #immediato | registro
⇒ Muove i dati da un registro a un’altro
Istruzioni aritmetiche
ADD R_dest, registro, #immediato | registro
⇒ Somma valoriSUB R_dest, registro, #immediato | registro
⇒ Sottrazione valoriIstruzioni logiche
AND R_dest, registro, #immediato | registro
⇒ Operazione and bit a bitORR R_dest, registro, #immediato | registro
⇒ Operazione or bit a bitEOR R_dest, registro, #immediato | registro
⇒ Operazione xor bit a bitBIC R_dest, registro, registro
⇒ (Bit Clear) R2 maschera in R3 i bit di R2MVN R_dest, registro
⇒ (Move Not) complemento a due, nega ogni bit nella dest.