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!



  1. No trackbacks yet.

Lascia una risposta

L'indirizzo email non verrà pubblicato. I campi obbligatori sono contrassegnati *

È possibile utilizzare questi tag ed attributi XHTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>