03.d ARM esempi di programmi ASM C. Fantozzi, A. Gardich (revisione di S. Congiu) EsA1: copia di un vettore Nel progettare un programma che esegua la copia di un vettore vanno definiti: i dati su cui il programma opera: sia quelli inizializzati, che hanno già un valore iniziale prima che inizi l esecuzione del programma (nell esempio il vettore da copiare può essere di questo tipo), sia quelli non inizializzati, nei quali verranno scritti dei valori durante l esecuzione del programma (nell esempio il vettore che riceve la copia può essere di questo tipo); le istruzioni che, operando su quei dati, realizzano quanto richiesto. 1
EsA1: dati inizializzati (.data) Il vettore da copiare, contenente ad es. una stringa di caratteri (480 byte = 120 word), può esser collocato nella sezione.data, tramite la direttiva (.ascii); in questo modo il vettore viene caricato in memoria (all indirizzo vett1), prima dell inizio del programma:.data vett1:.ascii "Registers R0 to R7 are unbanked registers. This me".ascii "ans that each of them refers to the same 32-bit ph".ascii "ysical register in all processor modes. They are c".ascii "ompletely general-purpose registers, with no speci".ascii "al uses implied by the architecture, and can be us".ascii "ed wherever an instruction allows a general-purpos".ascii "e register to be specified. Registers R8 to R14 ar".ascii "e banked registers. The physical register referred".ascii "to by each of them depends on the current processo".ascii "r mode. Where a particular phy" 2 EsA1: dati non inizializzati(.bss.bss) Nella sezione contenente i dati non inizializzati (.bss), si può collocare il vettore destinato a ricevere la copia (vett2): 3.bss vett2:.skip 480 @ spazio di 480 byte
EsA1: le istruzioni Conviene prevedere di mantenere nei registri le informazioni che servono per realizzare l algoritmo: R0: lunghezza del vettore in word, R1: indirizzo primo elemento di vett1 (vettore sorgente), R2: indirizzo primo elemento di vett2 (vett. destinazione). Il cuore del programma: 4 loop: MOV R0, R0, LSL#2@ lunghezza vettore in BYTE ADD R0, R1, R0 @ R0: indirizzo di stop (indirizzo @ successivo all ultimo elemento) LDR R3, [R1], #4 @ carica un word dal 1.mo vettore STR R3, [R2], #4 @ salva il word nel 2.do vettore CMP R1, R0 @ raggiunta la fine? BLO loop @ no: riesegue il loop EsA1: cuore del programma Modi di indirizzamento usati: di registro, di registro scalato, post-incremento immediato. Viene usato R3 (come registro di transito dei dati). 5 MOV R0, R0, LSL#2 ADD R0, R1, R0 loop: LDR R3, [R1], #4 STR R3, [R2], #4 CMP R1, R0 BLO loop @ lunghezza v.re in BYTE @ R0: indirizzo di stop (indirizzo @ successivo all ultimo elemento) @ carica un word dal primo v.re @ salva il word nel secondo v.re @ raggiunta la fine? @ no: riesegue il loop
EsA1: il programma completo Si può costruire ora il programma completo; l ambiente di programmazione richiede che: la prima istruzione da eseguire si trovi all indirizzo _start il simbolo _start sia dichiarato con l attributo.global prima delle istruzioni viste, vanno inserite le istruzioni che inseriscono nei registri i valori di inizializzazione. 6 EsA1: le istruzioni (.text(.text) Si usa LDR R1, =vett1 (anziché ADR R1, vett1) perché vett1 è definito in un segmento diverso da.text L istruzione finale (trap: B trap) serve a non perdere il controllo del processore alla fine del programma 7.global _start.text _start: MOV R0, #120 @ il vettore è lungo 120 word LDR R1, =vett1 @ indirizzo del v.re sorgente LDR R2, =vett2 @ indirizzo del v.re dest. copyvec: MOV R0, R0, LSL #2 @ lunghezza del v.re in Byte ADD R0, R1, R0 @ indirizzo di stop in R0 loop: LDR R3, [R1], #4 @ carica un word dal 1.mo v.re STR R3, [R2], #4 @ salva il word nel 2.do v.re CMP R1, R0 @ raggiunta la fine? BLO loop @ no: riesegue il loop trap: B trap @ fine programma
EsA1: versione più efficiente Indirizzo di stop in R0: è stato ottenuto con una sola istruzione (anziché due), usando l indirizzamento di registro scalato; con le istruzioni LDM e STM si copiano 10 word alla volta!.global _start.text _start: MOV R0, #120 @ il vettore è lungo 120 word LDR R1, =vett1 @ indirizzo del v.re sorgente LDR R2, =vett2 @ indirizzo del v.re destinaz. copyvec1:add R0, R1, R0, LSL #2 @ indirizzo di stop in R0 loop: LDMIA R1!, {R3-R12} @ carica 10 word dal 1.mo v.re STMIA R2!, {R3-R12} @ salva 10 word nel 2.do v.re. CMP R1, R0 @ raggiunta la fine? BLO loop @ no: riesegue il loop trap: B trap @ fine programma 8 EsA2: lunghezza di una stringa Si vuole scrivere un programma che calcoli la lunghezza di una stringa. La stringa in memoria sia terminata dal codice di controllo EOS (End Of String): byte con tutti i bit uguali a zero, che indica la line della stringa. 9
EsA2: sezioni.data e.bss 10 Il programma non fa uso di dati non inizializzati: la sezione.bss non c è. /* Dati inizializzati (stringa) */ str1:.data.ascii "Questa stringa e' lunga 36 caratteri".byte 0 @ EOS (terminatore di stringa).align @ allineamento a indir. di word EsA2: uso dei registri R0: contenga, all inizio, l indirizzo del primo carattere della stringa; R1: contenga, alla fine, la lunghezza della stringa, cioè il numero di caratteri di cui è costituita (EOS escluso). 11
EsA2: le istruzioni (.text(.text) esempio di istruzioni eseguite sotto condizione; esempio di indirizzamento con offset da registro. 12.global _start.text _start: LDR R0, =str1 @ puntatore alla stringa str1 strlen: MOV R1, #0 @ R1: lunghezza stringa loop: LDRB R2, [R0, R1] @ carica byte all'ind. R0+R1 CMP R2, #0 @ e' fine stringa (EOS)? ADDNE R1, R1, #1 @ no: conteggia il carattere BNE loop @ esamina quello successivo trap: B trap @ fine programma EsA3: fattoriale Si vuole scrivere un programma che calcoli il fattoriale di un numero 13 n ( n 1)! n! = 1 pern pern > 0 = 0
EsA3 : sezioni.data e.bss Il programma non fa uso di dati inizializzati: la sezione.data non c è; Il programma non fa uso di dati non inizializzati: la sezione.bss non c è. 14 EsA3 : uso dei registri 15 R0: contenga: all inizio, il numero n di cui calcolare il fattoriale; alla fine: n! (il fattoriale di n), 0 in caso di overflow.
EsA3: sezione.text.global _start.text _start: MOV R0, #6 @ da calcolare 6!=720=0x02D0 fact: CMP R0, #12 @ 13! non ci sta in 32 bit BLS do_it @ non c'e' overflow: procedi MOV R0, #0 @ c'e' overflow: poni R0=0 B fine @ fine programma do_it: MOV R1, R0 @ N ciclo: SUBS R1, R1, #1 @ R1=N-1 BEQ fine @ se R1=0 il ciclo e' finito MUL R0, R1, R0 @ R0=R1*R0 = N*(N-1) B ciclo @ vai all'iterazione successiva fine: trap: B trap @ fine programma 16 EsA3: versione più efficiente usando le istruzioni condizionate si ottiene codice con meno istruzioni. 17 _start: MOV R0, #6 @ da calcolare 6!=720=0x02D0 fact: CMP R0, #12 @ 13! non ci sta in 32 bit BLS do_it @ non c'e' overflow: procedi MOV R0, #0 @ c'e' overflow: poni R0=0 B fine @ fine programma do_it: MOV R1, R0 @ N ciclo: SUBS R1, R1, #1 @ R1=N-1 MULNE R0,R1,R0 @ R0=R1*R0 se R1 diverso da 0 BNE ciclo @ iteraz. successiva se R1=0 fine: trap: B trap @ fine programma
EsA3: compilatore c Come si comporta il compilatore c? unsigned int main() { 18 unsigned int r0=6; unsigned int r1; r1=r0; while(r1>1) { r1--; r0*=r1; } } return r0; EsA3: O1/livello di ottimizzazione 1 i commenti sono stati aggiunti (non sono stati prodotti dal compilatore) unsigned int r0=6; 0: e3a00006 mov r0, #6 unsigned int r1; r1=r0; 4: e1a0c000 mov r12, r0 @ N while(r1>1) { r1--; r0*=r1; } 8: e24cc001 sub r12, r12, #1 @ N=N-1 c: e000009c mul r0, r12, r0 @ R0=N*(N-1) 10: e35c0001 cmp r12, #1 @ R12>1? 14: 91a0f00e movls pc, lr @ no: fine 18: eafffffa bhi 8 @ si: itera
Fine 03.d esempi di programmi ASM