1.06 Lezione 6 - follen99/ArchitetturaDeiCalcolatori GitHub Wiki

📅 03-18 0:22

Registri - continuo

I registri da t0-t6 sono dei registri temporanei, e quindi il callee non è obbligato a preservarne il contenuto; traduzione: possiamo sporcarli come ci pare e piace.

D'altro canto, i registri s0-s11 sono registri save ed il loro contenuto deve essere preservato. Se il chiamante (callee) li utilizza, è obbligato a preservarne il contenuto, dobbiamo quindi salvare il contenuto dei registri save che utilizziamo nella funzione, attraverso lo stack (visto nella lezione precedente.)

Ovviamente iniziamo prima a scrivere il codice utilizzando i registri che ci servono, poi, a codice finito, ci curiamo di scrivere la parte di codice che salva i registri S.

Procedure non-foglia

Le procedure non foglia sono delle funzioni che chiamano altre funzioni.

Esempio in C

int fact (int n){
  if (n < 1) return 1;
  else return n * fact(n - 1);
}

Codice scritto in C di un fattoriale ricorsivo

Quando non è strettamente necessario, è sempre meglio non utilizzare una funzione ricorsiva; questo per vari motivi, ma il più evidente lo vedremo tra poco con il codice assembly

Programma assembly

fact:
	addi sp, sp, -16	# facciamo spazio per salvare i due registri, ra e a0
	sd	ra, 8(sp)
	sd	a0, 0(sp)
	
	addi	t0, a0, -1
	
	bge	t0, zero, L1
	addi	a0, zero, 1
	addi 	sp, sp, 16
	
	jalr	zero, 0(ra)
  
L1:	
	addi	a0, a0, -1
	jal	ra, fact
	addi	t1, a0, 0
	
	ld	a0, 0(sp)
	ld	ra, 8(sp)
	addi	sp, sp, 16
	mul	a0, a0, t1
	jalr 	zero, 0(ra)

Dobbiamo ovviamente salvare il return address, che verrà inevitabilmente sporcato nel momento in cui la funzione chiama un'altra funzione. Va ovviamente recuperato in uscita dallo stack.

Layout di memoria

Come detto precedentemente, nell'area Text è presente il codice del programma, posto solitamente agli indirizzi più bassi dopo la zona riservata al sistema operativo (non in foto, ma molto giù).

Successivamente sono presenti i dati static, e sono dati che rimangono presenti in memoria indipendentemente dal programma e dallo stack; ci sono infatti le variabili static, ovvero delle variabili dichiarate all'interno delle funzioni ma dichiarate come static var, in modo da allocarle nell'area static e non nello stack. Esempio: voglio ad esempio contare il numero di volte in cui la funzione viene eseguita, non posso quindi utilizzare una variabile della funzione (con scope all'interno della funzione), ma una variabile static che viene incrementata ogni volta. Questo tipo di variabile non può essere cancellata, inoltre tutte le stringhe vengono allocate in questa parte della memoria. Possiamo anche dichiarare una funzione statica; questo serve a: quando vado a compilare diversi files (moduli) separati, ci serve a dire che una determinata funzione non deve essere vista ad altri moduli. Questo serve a prevenire a fare danni nel momento in cui due funzioni su due moduli diversi vengono dichiarati con lo stesso nome; queste funzioni non vengono esportate al linker, che ne ignorerà il nome.

Caratteri - dati

Il modo classico di codificare i caratteri di testo, è quello di usare un singolo byte, quindi 8 bit. In questo byte vengono scritti i caratteri in codice ASCII, che permette di codificare 128 caratteri diversi, dove 95 sono grafici, e 33 di controllo.

Operazioni Byte, Halfword, Word

operazioni di load

  • lb rd, offset(rs1) 8 bit
  • lh rd, offset(rs1) 32 bit
  • lw rd, offset(rs1) 64 bit

operazioni di load unsigned

Queste operazioni effettuano l'estensione del segno, se sto prendendo caratteri del set ASCII esteso, e voglio evitare il segno, devo usare queste operazioni. Possiamo quindi leggere un singolo carattere da una stringa, non usare lb!

  • lbu rd, offset(rs1)
  • lhu rd, offset(rs1)
  • lwu rd, offset(rs1)

operazioni di load

  • sb rs2, offset(rs1)
  • sh rs2, offset(rs1)
  • sw rs2, offset(rs1)

Esempio di copia stringa

Esempio in C

void strcpy (char x[], char y[]){
  size_t i;
  i = 0;
  while ((x[i] = y[i]) != '\0')	// assegno il carattere all'altro array finchè non trovo un terminatore (non faccio confronti!)
    i += 1;
}

Codice assembly

strcpy:
	addi sp, sp, -8
	sd	s3, 0(sp)
	add s3, zero, zero
	
L1:
	add t0, s3, a1
	lbu t1, 0(t0)
	add t2, s3, a0
	sb t1, 0(t2)
	beq t1, zero, L2
	addi s3, s3, 1
	jal zero, L1
	
L2:
	ld s3, 0(sp)
	addi sp, sp, 8
	jalr zero, 0(ra)

🏁 FINE LEZIONE 6

⚠️ **GitHub.com Fallback** ⚠️