uniroma1
.*_main.c
.cognome.nome
. Sulle postazioni del laboratorio (VM BIAR Arch) sarà /home/studente/Desktop/cognome.nome/
.cognome.nome.zip
(zip -r cognome.nome.zip cognome.nome/
).cognome.nome.zip
.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 realizza un comparatore per tipi int
:
int comp(void* xv, void* yv) {
int* x = (int*)xv;
int* y = (int*)yv;
return *x - *y;
}
Nota: in IA32 i puntatori non hanno tipo e sono semplicemente dei contenitori che denotano indirizzi, cioè interi senza segno. Pertanto il cast (int*)
è come se non ci fosse nella traduzione IA32.
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 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
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 realizza la funzione di confronto di stringhe C strcmp
come specificato dallo standard POSIX:
char my_strcmp(const char* s1, const char* s2) {
while (*s1 && *s1 == *s2) {
s1++;
s2++;
}
return *s1 - *s2;
}
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 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
compilando con gcc e4_main.c e4.c -o e4
.
Rispondere ai quiz riportati nel form di consegna.
.global comp
comp:
movl 4(%esp), %eax
movl 8(%esp), %ecx
movl (%eax), %eax
subl (%ecx), %eax
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:
char my_strcmp(const char* s1, const char* s2) {
const char* c = s1;
const char* d = s2;
L:; char a = *c;
if (a == 0) goto E;
if (a != *d) goto E;
c++;
d++;
goto L;
E: a = a - *d;
return a;
}
IA32:
.global my_strcmp
my_strcmp: # char my_strcmp(const char* s1, const char* s2) {
movl 4(%esp), %ecx # const char* c = s1;
movl 8(%esp), %edx # const char* d = s2;
L: movb (%ecx), %al # ; char a = *c;
testb %al, %al # if (a == 0)
je E # goto E;
cmpb (%edx), %al # if (a != *d)
jne E # goto E;
incl %ecx # c++;
incl %edx # d++;
jmp L # goto L;
E: subb (%edx), %al # a = a - *d;
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?
x & 1 == 0
[se il bit meno significativo è zero allora il numero è 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]