uniroma1.*_main.c.cognome.nome. Sulle postazioni del laboratorio sarà /home/studente/Desktop/cognome.nome/.cognome.nome.zip (zip -r cognome.nome.zip cognome.nome/).cognome.nome.zip.E1/e1_eq.c equivalente a quella di partenza, ma più semplice da tradurre in assembly. Testatela con il main di prova prima di passare a scrivere la versione .s. E’ inutile tradurre la versione C equivalente se è errata!Per maggiori informazioni fate riferimento al regolamento delle esercitazioni.
Tradurre nel file E1/e1.s la seguente funzione C contenuta in E1/e1.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 E1 compilando con gcc -m32 e1_main.c e1.s -o e1.
Tradurre nel file E2/e2.s la seguente funzione C contenuta in E2/e2.c che, dati due array di short, conta in numero di indici per cui gli array hanno lo stesso valore:
int counteq(short* v1, short* v2, int n) {
int i, cnt = 0;
for (i=0; i<n; ++i) cnt += (v1[i]==v2[i]);
return cnt;
}
Suggerimento: usare le istruzioni SETcc e MOVZ/MOVS.
Usare il main di prova nella directory di lavoro E2 compilando con gcc -m32 e2_main.c e2.s -o e2.
Tradurre nel file E3/e3.s la seguente funzione C contenuta in E3/e3.c che clona un blocco di memoria di n byte all’indirizzo src.
Il nuovo blocco deve essere allocato con malloc e deve avere lo stesso contenuto del blocco src. Sarà compito del chiamante di clone deallocare il blocco di memoria allocato da clone.
#include <stdlib.h>
#include <string.h>
void* clone(const void* src, int n) {
void* des = malloc(n);
if (des==0) return 0;
memcpy(des, src, n);
return des;
}
Suggerimento: per copiare i dati src al nuovo blocco si suggerisce di usare la funzione memcpy. Si noti che è possibile chiamare funzioni di libreria C con call come se fossero normali funzioni scritte dall’utente.
Usare il main di prova nella directory di lavoro E3 compilando con gcc -m32 e3_main.c e3.s -o e3.
Scrivere nel file E4/e4.c una funzione C drop_spaces che, data una stringa text, elimina tutti gli spazi.
void drop_spaces(char* text);
Usare il main di prova nella directory di lavoro E4 compilando con gcc e4_main.c e4.c -o e4.
foo ha un prologo in cui vengono salvati due registri callee-save e vengono riservati 12 byte per ospitare variabili locali, argomenti ed eventuale padding, quale di questi operandi permette di accedere al secondo argomento di foo?
Se una funzione foo ha un prologo in cui vengono salvati due registri callee-save e vengono riservati 12 byte per ospitare variabili locali, argomenti ed eventuale padding, quale di questi operandi permette di accedere al secondo argomento di foo?
(%esp)4(%esp)8(%esp)12(%esp)20(%esp)24(%esp)28(%esp)32(%esp)%al = 5, eseguire movsbl %al, %eax porta allo stesso risultato in %eax rispetto eseguire movzbl %al, %eax?
foo che chiama una funzione baz. Quale tra le seguenti affermazioni risulta essere vera:
foo non può utilizzare il registro %eaxfoo non può utilizzare il registro %ebxbaz non può utilizzare il registro %eaxbaz non può utilizzare il registro %ebxbaz viene chiamata da una funzione foo, quale delle seguenti affermazioni risulta essere falsa:
baz prima di poter utilizzare %edi deve salvare il suo contenuto e ripristinarlo prima di effettuare la retbaz può utilizzare %edx senza dover preservare il suo contenuto inizialefoo deve salvare il contenuto di %ecx se vuole preservarne il contenuto prima di chiamare bazfoo deve salvare il contenuto di %esi se vuole presevarne il valore prima di chiamare bazsetl %eaxsetba %alleal (%eax, %edx, 6), %ecxmovl (%eax), 4(%esp)leal -1(%ecx), %eaxaddl %eax, $4%eax=0x0000BEEF, quanto vale %ecx dopo aver eseguito l’istruzione movsbw %al, %cx?
0x000000EF0xFFFFFFEF0x0000FFEF0x0000EFEFSe %ecx=0, qual è il valore di %al dopo le istruzioni testl %ecx, %ecx e setge %al
Rispondere ai quiz riportati nel form di consegna.
Video esplicativo della soluzione
e1_eq.c
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;
}
e1.s
.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;
e2_eq.c
int counteq(short* v1, short* v2, int n) {
short* di = v1;
short* si = v2;
int d = n;
int a = 0;
d--;
L: if (d<0) goto E;
short c = di[d];
short b = si[d];
char cl = c == b ? 1 : 0;
int cc = (int)cl;
a = a + cc;
d--;
goto L;
E: return a;
}
e2.s
.globl counteq
counteq: # int counteq(short* v1, short* v2, int n)
pushl %edi # prologo
pushl %esi
pushl %ebx
movl 16(%esp), %edi # short* di = v1;
movl 20(%esp), %esi # short* si = v2;
movl 24(%esp), %edx # int d = n;
xorl %eax, %eax # int a = 0;
decl %edx # d--;
L: testl %edx, %edx # if (d<0)
jl E # goto E;
movw (%edi, %edx, 2), %cx # short c = di[d];
movw (%esi, %edx, 2), %bx # short b = si[d];
cmpw %cx, %bx # char cl =
sete %cl # c == b ? 1 : 0;
movsbl %cl, %ecx # int cc = (int)cl;
addl %ecx, %eax # a = a + cl;
decl %edx # d--;
jmp L # goto L;
E:
popl %ebx # epilogo
popl %esi
popl %edi
ret # return a;
e3_eq.c
#include <stdlib.h>
#include <string.h>
void* clone(const void* src, int n) {
const void* si = src;
int b = n;
void* a = malloc(n);
void* di = a;
if (di==0) goto N;
memcpy(di, si, b);
a = di;
return a;
N: a = 0;
return a;
}
e3.s
.global clone
clone: # void* clone(const void* src, int n) {
pushl %esi # prologo
pushl %edi
pushl %ebx
subl $12, %esp
movl 28(%esp),%esi # const void* si = src;
movl 32(%esp),%ebx # int b = n;
movl %ebx, (%esp) # b;
call malloc # void* a = malloc( )
movl %eax, %edi # void* di = a
xorl %eax, %eax # a = 0;
testl %edi, %edi # if (di==0)
je E # goto E;
movl %edi, (%esp) # di
movl %esi, 4(%esp) # | si
movl %ebx, 8(%esp) # | | b
call memcpy # memcpy( | , | ,| );
movl %edi, %eax # a = di;
E:
addl $12, %esp # epilogo
popl %ebx
popl %edi
popl %esi
ret # return a;
e4.c
void drop_spaces(char* text) {
char* s = text;
while(*text)
if (*text == ' ') text++;
else *s++ = *text++;
*s = '\0';
}
Risposte corrette ai quiz:
1) G. 28(%esp)
2) A. Sì
3) E. Nessuna delle precedenti affermazioni è vera
4) D. foo deve salvare il contenuto di %esi se vuole presevarne il valore prima di chiamare baz`
5) E. leal -1(%ecx), %eax
6) C. 0x0000FFEF
7) B. 1