Sistemi di Calcolo

Corso di Laurea in Ingegneria Informatica e Automatica

Home | Avvisi | Diario Lezioni | Esercitazioni | Esami | Materiale Didattico | Valutazioni Studenti | Lezioni di Camil Demetrescu |

[T04] Esercitazione 4

Istruzioni per l’esercitazione:

Per maggiori informazioni fate riferimento al regolamento delle esercitazioni.

Esercizio 1 (debugging)

Data la funzione C:

int count(const char *s1){
    int a=0;
    while(*s1){
        a++;
        s1++;
    }
    return a;
}

Uno studente ha tradotto la funzione in ASM nel file E1-count/e1.s. Purtroppo la traduzione presenta alcuni errori. Infatti, generando il binario con gcc -m32 e1_main.c e1.s -o e1 -g, la funzione non calcola il risultato corretto:

> ./e1
Test 1: 0 [corretto: 0]
Test 2: 0 [corretto: 3]
Test 3: 0 [corretto: 24]
Risultato: 1/3

Usare GDB per analizzare step by step l’esecuzione ed identificare gli errori. Infine, correggere gli errori.

Esercizio 2 (ricerca in un array)

Tradurre nel file E2-find/e2.s la seguente funzione C contenuta in E2-find/e2.c che cerca un intero in un array:

int find(int* v, int n, int x) {
    int i;
    for (i=0; i<n; ++i)
        if (v[i] == x) return 1;
    return 0;
}

Suggerimento: provare a riformulare il codice C in una forma equivalente in modo che usi solo tre variabili.

Usare il main di prova nella directory di lavoro E2-find compilando con gcc -m32 e2_main.c e2.s -o e2.

Esercizio 3 (Numeri di Fibonacci)

Tradurre nel file E3-fib/e3.s la seguente funzione C contenuta in E3-fib/e3.c che calcola i numeri di Fibonacci:

int fib(int n) {
    if (n<2) return 1;
    return fib(n-1)+fib(n-2);
}

Usare il main di prova nella directory di lavoro E3-fib compilando con gcc -m32 e3_main.c e3.s -o e3.

Esercizio 4 (Palestra C)

Scrivere nel file E4-count-substrings/e4.c una funzione dal seguente prototipo che, data una stringa s e una stringa sub, calcola il numero di posizioni distinte in s in cui sub appare come sottostringa:

int count_substrings(const char* s, const char* sub);

Usare il main di prova nella directory di lavoro E4-count-substrings compilando con gcc e4_main.c e4.c -o e4.

Domande

Domanda 1) L’operando (%eax, %ecx, 5) è valido?

Domanda 2) Si consideri la variabile int* p e si assuma che venga tenuta nel registro %eax. A quale istruzione assembly corrisponde l’istruzione C p++?

Domanda 3) Quali delle seguenti operazioni IA32 permette di azzerare il registro %eax?

Domanda 4) Quali dei seguenti predicati C permette di verificare se la variabile int x contiene un valore pari?

Domanda 5) Come tradurresti in IA32 l’assegnamento v[5] = 7, assumendo che v sia int* e sia tenuto nel registro %eax?

Domanda 6) Si consideri la riga di comando gcc main.c prova.s -o prova su una piattaforma a 64 bit. Dove prova.s è un codice IA32. Che esito probabile ti aspetteresti?

Soluzioni

Esercizio 1 (debugging)

IA32:

.globl count

count:                                       # int count(const char *s1){
    xorl %eax, %eax                          # int a=0;
    movl 4(%esp), %ecx                       # const char* c = s1;
A:  cmpb $0, (%ecx)    # errore 1            # if(!*c) goto E;
    je E               # errore 2
    incl %eax                                # a++;
    incl %ecx                                # c++;
    jmp A                                    # goto A;
    
E:  ret
Esercizio 2 (ricerca in un array)

C equivalente:

int find(int* v, int n, int x) {
    int* c = v;
    int  d = n;
    int  a = x;
    d--;
L:  if (d < 0)     goto R0;
    if (c[d] == a) goto R1;
    d--;
    goto L;
R0: a = 0;
    return a;
R1: a = 1;
    return a;
}

IA32:

.global find

find: # int find(int* v, int n, int x) {
    movl 4(%esp), %ecx         # int* c = v;
    movl 8(%esp), %edx         # int  d = n;
    movl 12(%esp), %eax        # int  a = x;
    decl %edx                  # d--;
L:  testl %edx, %edx           # if (d < 0)
    jl R0                      # goto R0;
    cmpl %eax, (%ecx,%edx,4)   # if (c[d] == a)
    je R1                      # goto R1;
    decl %edx                  # d--;
    jmp L                      # goto L;
R0: xorl %eax, %eax            # a = 0;
    ret                        # return a;
R1: movl $1, %eax              # a = 1;
    ret                        # return a;
Esercizio 3 (Numeri di Fibonacci)

C equivalente:

int fib(int n) {
    int di = n;
    int a = 1;
    if (di<2) goto E;
    di--;
    a = fib(di);
    int b = a;
    di--;
    a = fib(di);
    a = a + b;
E:  return a;
}

IA32:

.globl fib

fib:                        # int fib(int n)
    pushl %edi              # prologo
    pushl %ebx
    subl $4, %esp

    movl 16(%esp), %edi     # int di = n;
    movl $1, %eax           # int a = 1;
    cmpl $2, %edi           # if (di<2)
    jl E                    #     goto E;
    decl %edi               # di--;
    movl %edi, (%esp)       #         di
    call fib                # a = fib( | )
    movl %eax, %ebx         # int b = a;
    decl %edi               # di--;
    movl %edi, (%esp)       #         di
    call fib                # a = fib( | )
    addl %ebx, %eax         # a = a + b;

E:  addl $4, %esp           # epilogo
    popl %ebx
    popl %edi
    ret                     # return a;
Esercizio 4 (Palestra C)
static int is_prefix(const char* sub, const char* s) {
    while (*sub == *s && *sub!=0 && *s!=0) {
        sub++;
        s++;
    }
    return *sub == 0;
}

int count_substrings(const char* s, const char* sub) {
    int cnt = 0;
    do cnt += is_prefix(sub,s); while(*s++);
    return cnt;
}
Domande

Domanda 1) L’operando (%eax, %ecx, 5) è valido?

Domanda 2) Si consideri la variabile int* p e si assuma che venga tenuta nel registro %eax. A quale istruzione assembly corrisponde l’istruzione C p++?

Domanda 3) Quali delle seguenti operazioni IA32 permette di azzerare il registro %eax?

Domanda 4) Quali dei seguenti predicati C permette di verificare se la variabile int x contiene un valore pari?

Domanda 5) Come tradurresti in IA32 l’assegnamento v[5] = 7, assumendo che v sia int* e sia tenuto nel registro %eax?

Domanda 6) Si consideri la riga di comando gcc main.c prova.s -o prova su una piattaforma a 64 bit. Dove prova.s è un codice IA32. Che esito probabile ti aspetteresti?