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.rm -rf cognome.nome).Per maggiori informazioni fate riferimento al regolamento delle esercitazioni.
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.
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.
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.
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.
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++?
incl %eaxaddl $2,%eaxaddl $4,%eaxincw %axDomanda 3) Quali delle seguenti operazioni IA32 permette di azzerare il registro %eax?
movl $0, %eaxandl $0, %eaxxorl %eax, %eaxDomanda 4) Quali dei seguenti predicati C permette di verificare se la variabile int x contiene un valore pari?
x & 1 == 0x | 1 == 1x % 2 == 1Domanda 5) Come tradurresti in IA32 l’assegnamento v[5] = 7, assumendo che v sia int* e sia tenuto nel registro %eax?
movl $7, 5(%eax)movl $7, 10(%eax)movl $7, 20(%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?
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
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;
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;
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;
}
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++?
addl $4,%eax [p è un puntatore ad int: l’indirizzo in %eax va incrementato di 4 byte]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?
movl $7, 20(%eax) [l’elemento v[5] si trova a 20 byte da v in quanto è preceduto da 4 elementi di taglia 4 byte]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?
%esp (32bit) invece che %rsp (64bit) andando ad operare con indirizzi non validi]
–>