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.
NOTA: in caso di errore in fase di linking su memcpy per via di PIE, usare gcc -m32 e3_main.c e3.s -o e3 -no-pie
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?
(%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