Somma & Funzioni
Obbiettivo di questo esercizio è quello di scrivere un programma Assembly che, dati da un utente, 2 numeri, stampi una stringa che indichi la somma, passando i due valori (a e b) alla funzione s = somma(int a, int b).
Esempio in C:
#include <stdio.h> int somma (int a, int b) { int s; s = a + b; return s; } int main (void) { int a; int b; printf("Inserisci il valore di a: "); scanf("%i", &a); printf("Inserisci il valore di b: "); scanf("%i", &b); int s = somma(a,b); printf("La somma di a e b e': %i\n", s); return 0; }
Assembly – main.s
# Nome file # ---------- # main.s # Istruzioni per la compilazione # ------------------------------ # as -o main.o main.s -gstabs # ld -o main main.o .code32 # == PRIMA SEZIONE ============================================================= .section .data #sezione variabili globali ins_a: .ascii "Inserisci il valore di a: " ins_a_len: .long . - ins_a ins_b: .ascii "Inserisci il valore di b: " ins_b_len: .long . - ins_b stampa_somma: .ascii "Somma tra a e b: " stampa_somma_len: .long . - stampa_somma a_capo: .ascii "\n" a_capo_len: .long . - a_capo # == SECONDA SEZIONE =========================================================== .section .text # Sezione istruzioni. .global _start # Punto di inizio del programma. _start: leal ins_a, %ecx # Istruzioni per movl ins_a_len, %edx # la stampa a video movl $4, %eax # del messaggio di movl $1, %ebx # richiesta del primo valore da inserire. int $0x80 # Si richiama la funzione exit. call atoi # Chiamo il sottoprogramma per convertire da ascii a numero. pushl %eax # Salvo sullo stack il primo valore letto. leal ins_b, %ecx # Istruzioni per movl ins_b_len, %edx # la stampa a video movl $4, %eax # del messaggio di movl $1, %ebx # richiesta del secondo valore da inserire. int $0x80 # Si richiama la funzione exit. call atoi # Chiamo il sottoprogramma per convertire da ascii ad intero. popl %ebx # Rimette il primo valore in ebx. call somma # Richiamo la funzione somma. pushl %eax # Dato che la funzione di stampa sovrascrive eax, lo salvo in reg. leal stampa_somma, %ecx # Istruzioni per movl stampa_somma_len, %edx # la stampa a video movl $4, %eax # del messaggio di movl $1, %ebx # somma tra i due valori inseriti. int $0x80 # Si richiama la funzione exit. popl %eax # Recupero eax salvato precedentemente per la stampa. call itoa # Chiamo il sottoprogramma per convertire da intero ad ascii. leal a_capo, %ecx # Istruzioni per movl a_capo_len, %edx # la stampa a video movl $4, %eax # del messaggio di movl $1, %ebx # andare a capo. int $0x80 # Si richiama la funzione exit. jmp end # Fai una jump alla fine del programma. somma: addl %ebx, %eax # Eseguo la somma e salvo il eax. ret # Ritorno. end: movl $1, %eax # Istruzioni per xorl %ebx, %ebx # la chiusura int $0x80 # del programma.
Assembly – atoi.s
.code32 .section .data car: .byte 0 # la variabile car e' dichiarata di tipo byte .section .text .global atoi .type atoi, @function # dichiarazione della funzione atoi # la funzione converte una stringa di caratteri # proveniente da tastiera e delimitata da '\n' # in un numero che viene restituito nel registro eax atoi: pushl %ebx # salvo il valore corrente di ebx sullo stack pushl %ecx # salvo il valore corrente di ecx sullo stack pushl %edx # salvo il valore corrente di edx sullo stack xorl %eax, %eax inizio: pushl %eax movl $3, %eax # carica in eax il codice della chiamata di sistema read xorl %ebx, %ebx # azzera ebx (0=tastiera) leal car, %ecx # carica in ecx l'indirizzo di car in cui verra' salvato # il carattere letto mov $1, %edx # comanda di leggere un solo carattere int $0x80 # chiamata di sistema cmp $10, car # vedo se e' stato letto il carattere '\n' je fine subb $48, car # converte il codice ASCII della cifra nel numero corrisp. popl %eax movl $10, %ebx mull %ebx # eax = eax * 10 + car # sto trascurando i 32 bit piu' significativi del risultato # della moltiplicazione che sono in edx # quindi il numero introdotto da tastiera deve essere < di 2^32 addl car, %eax jmp inizio fine: popl %eax # ripristino dei registri salvati sullo stack # l'ordine delle pop deve essere inverso delle push popl %edx # ripristino il valore di edx all'inizio della chiamata popl %ecx # ripristino il valore di ecx all'inizio della chiamata popl %ebx # ripristino il valore di ebx all'inizio della chiamata ret # fine della funzione atoi # l'esecuzione riprende dall'istruzione sucessiva # alla call che ha invocato atoi
Assembly – itoa.s
#################################################################### ################### itoa.s ######################################### #################################################################### .code32 .section .data car: .byte 0 .section .text .global itoa .type itoa, @function itoa: mov $0, %ecx continua_a_dividere: cmp $10, %eax jge dividi pushl %eax inc %ecx mov %ecx, %ebx jmp stampa dividi: movl $0, %edx movl $10, %ebx divl %ebx pushl %edx inc %ecx jmp continua_a_dividere stampa: cmp $0, %ebx je fine_itoa popl %eax movb %al, car addb $48, car dec %ebx pushw %bx movl $4, %eax movl $1, %ebx leal car, %ecx mov $1, %edx int $0x80 popw %bx jmp stampa fine_itoa: movb $10, car movl $4, %eax movl $1, %ebx leal car, %ecx mov $1, %ecx int $0x80 ret
Per ogni dubbio, non esitate a commentare!
No trackbacks yet.