Anteprima
Vedrai una selezione di 14 pagine su 65
Appunti completi corso Architettura dei Calcolatori Pag. 1 Appunti completi corso Architettura dei Calcolatori Pag. 2
Anteprima di 14 pagg. su 65.
Scarica il documento per vederlo tutto.
Appunti completi corso Architettura dei Calcolatori Pag. 6
Anteprima di 14 pagg. su 65.
Scarica il documento per vederlo tutto.
Appunti completi corso Architettura dei Calcolatori Pag. 11
Anteprima di 14 pagg. su 65.
Scarica il documento per vederlo tutto.
Appunti completi corso Architettura dei Calcolatori Pag. 16
Anteprima di 14 pagg. su 65.
Scarica il documento per vederlo tutto.
Appunti completi corso Architettura dei Calcolatori Pag. 21
Anteprima di 14 pagg. su 65.
Scarica il documento per vederlo tutto.
Appunti completi corso Architettura dei Calcolatori Pag. 26
Anteprima di 14 pagg. su 65.
Scarica il documento per vederlo tutto.
Appunti completi corso Architettura dei Calcolatori Pag. 31
Anteprima di 14 pagg. su 65.
Scarica il documento per vederlo tutto.
Appunti completi corso Architettura dei Calcolatori Pag. 36
Anteprima di 14 pagg. su 65.
Scarica il documento per vederlo tutto.
Appunti completi corso Architettura dei Calcolatori Pag. 41
Anteprima di 14 pagg. su 65.
Scarica il documento per vederlo tutto.
Appunti completi corso Architettura dei Calcolatori Pag. 46
Anteprima di 14 pagg. su 65.
Scarica il documento per vederlo tutto.
Appunti completi corso Architettura dei Calcolatori Pag. 51
Anteprima di 14 pagg. su 65.
Scarica il documento per vederlo tutto.
Appunti completi corso Architettura dei Calcolatori Pag. 56
Anteprima di 14 pagg. su 65.
Scarica il documento per vederlo tutto.
Appunti completi corso Architettura dei Calcolatori Pag. 61
1 su 65
D/illustrazione/soddisfatti o rimborsati
Disdici quando
vuoi
Acquista con carta
o PayPal
Scarica i documenti
tutte le volte che vuoi
Estratto del documento

GLOBALI

- Sono piazzate in un indirizzo fisso stabilito dall'assemblatore e dal linker.

- Normalmente l'identificativo con cui accediamo ad esse coincide con il loro nome.

- L'ordine di dichiarazione nel codice coincide con l'ordine di collocamento in memoria.

All'interno della memoria sono nel segmento dati il quale parte da 0x10000000. Il Global

Pointer è inizializzato a 0x10008000 così possiamo fare offset avanti e indietro. Prima del

segmento dati, da 0x00400000 a 0x10000000 c'è il segmento di testo. Tutto ciò che viene

prima del segmento di testo è riservato al processore. La pila parte da 0x7fffffff andando

all'indietro. Da 0x80000000 in poi è riservato al sistema operativo.

.data

C: .byte 64 # char C = '@';

A: .word 1 # int A = 1;

B: .half # short B;

VET: .space 40 # int VET[10];

PUNT1: .word 0 # int* PUNT1 = NULL;

PUNT2: .word # char* PUNT2;

Da questo codice che alloca alcune variabili, possiamo elencate le principali direttive

dell'assemblatore e il loro significato:

.data <addr> Dichiara il segmento dati a partire dall'indirizzo dato

.asciiz “str” Memorizza una stringa terminandola con il carattere nullo

.ascii “str” Memorizza una stringa senza il terminatore

.byte b1,...bn Memorizza dati contigui da un byte

.word w1,...wn Memorizza dati contigui da una word

.half h1,...hn Memorizza dati contigui da una half word

.space n Alloca n byte contigui

.text <addr> Dichiara il segmento di testo a partire dall'indirizzo dato

.globl sym Dichiara un'etichetta globale visibile dagli altri file

.eqv Sostituisce il secondo operando al primo come il #define nel C

Un bell'esempio con somma di un array (l'ho scritto io e ci ho messo un'ora lelz):

.data 0x10000000

ARRAY: .word 1,2,3,4,5,6,7,8,9,10

RESULT: .word 0

.text 0x00400000

.globl main

main: lw $t0, ARRAY # carica primo elemento array

lw $s0, RESULT # carica variabile risultato

la $t2, ARRAY # memorizza indirizzo array

NEXT: add $s0, $s0, $t0 # incrementa RESULT

slti $t1, $t0, 10 # condizione di terminazione

beq $t1, $0, END

addi $t2, $t2, 4 # indirizzo prossimo elemento

lw $t0, ($t2) # carica prossimo elemento

j NEXT # loop

END: sw $s0, RESULT # memorizza risultato finale

LOCALI

Le variabili locali entrano in gioco quando si parla di funzioni. I primi quattro parametri

vanno passati negli appositi registri a0, a1, a2, a3:

Se sono di tipo scalare o un puntatore a 32 bit;

– Gli array sono considerati puntatori al primo elemento;

– Per passare una struct dipende dal compilatore (di solito indirizzo primo elemento).

Nel raro caso in cui una funzione abbia più di quattro parametri bisogna inserirli nella pila.

Ed è un bel casino che vedremo dopo D:

I valori si ritorno invece vanno inseriti nel registro v0 e valgono le stesse tre regole dei

parametri in ingresso. Nel caso in cui il valore sia un numero in virgola mobile si usa anche

il registro v1. Le variabili locali poi possono essere gestite in vari modi:

Scalari e puntatori

In un registro tra s0-s7 se non è richiesto l'uso del loro indirizzo di memoria

– Nell'area di attivazione della funzione

Scalare accessibile attraverso puntatori

Solo nell'area di attivazione della funzione, perché richiede un indirizzo

Array e struct

Solo nell'area di attivazione della funzione

Un altro esempio bastardo che ho fatto io con tanta pazienza: un array di 5 elementi uguali

a zero, prendiamo gli ultimi tre e ci aggiungiamo sei.

.data 0x10000000

VET: .space 20

A: .word 2

.text 0x00400000

.globl main

main: li $t0, 5 # carica 5 (lunghezza array)

FOR: lw $s0, A # carica indice

slt $t1, $s0, $t0 # se (A < 5) continua

beq $t1, $0, END

la $t2, VET # carica VET[0]

sll $s0, $s0, 2 # indirizzamento da word a byte

add $t2, $t2, $s0 # aggiungi offset primo elemento

lw $s1, ($t2) # carica VET[A]

addi $s1, $s1, 6 # aggiungi 6

sw $s1, ($t2) # memorizza VET[A]

srl $s0, $s0, 2 # indirizzamento da byte a word

addi $s0, $s0, 1 # incrementa contatore

sw $s0, A # memorizza A

j FOR

END:

SYSTEM CALL

Alcune funzionalità sono molto ricorrenti in ogni programma e sarebbe bello se non

dovessimo riprogrammarle noi ogni volta, per esempio la stampa a video o la lettura da

tastiera (che sono in realtà cose piuttosto complicate da fare, quindi è bene avere queste

funzionalità già pronte e gestite dal sistema operativo). Questi servizi si chiamano system

call, cioè “chiamate al sistema”.

Ogni system call ha un numero identificativo, dei parametri ed eventualmente un valore di

ritorno. Alcuni esempi:

print_int Stampa un intero

print_string Stampa una stringa (terminata con il carattere nullo)

read_int Legge un numero fino al carattere a capo incluso

read_string Legge una stringa di a1 caratteri, la memorizza in un buffer a0

e la termina con il carattere nullo

exit Interrompe l'esecuzione di un programma

Nome Codice Argomenti Risultato

print_int 1 $a0

print_float 2 $f12

print_double 3 $f12

print_string 4 $a0

read_int 5 $v0

read_float 6 $f0

read_double 7 $f0

read_string 8 $a0, $a1

sbrk 9 $a0 $v0

exit 10

Per poter usare queste funzioni bisogna:

Caricare il codice della system call in $v0;

– Caricare gli argomenti negli appositi registri (se richiesti);

– Eseguire syscall;

– Estrarre gli eventuali valori di ritorno.

Esempio di un programma che stampa a video “La risposta e' 5”

.data 0x10000000

str: .asciiz “La risposta e'”

.text 0x00400000

li $v0 4 # codice della print_string

la $a0, str # carica indirizzo stringa

syscall # stampa della stringa

li $v0, 1 # codice della print_int

li $a0, 5 # carica 5

syscall # stampa dell'intero

li $v0, 10 # codice della exit

syscall # termina programma

Vediamo nello specifico come gestire i SOTTOPROGRAMMI (aka funzioni) in MIPS

perché sono un po' complicate.

Nei linguaggi di alto livello la chiamata a funzione crea un record di attivazione nella

cima dello stack. La presenza di più funzioni in esecuzione semplicemente provoca

l'impilamento di più record uno sopra l'altro. Al termine di una funzione il corrispettivo

record viene deallocato. Il main è il primo record che viene allocato in memoria, ed esiste

per tutta l'esecuzione del programma.

Ogni record contiene queste informazioni:

Parametri in ingresso con i loro valori

– Indirizzo di ritorno

– Informazioni sulla gestione della memoria nel record

– Variabili locali

– Valore di ritorno

Cosa succede a basso livello?

Il chiamante (CALLER) gestisce il passaggio dei parametri;

– Il chiamante attiva il sottoprogramma tramite l'istruzione apposita;

– L'istruzione di chiamata gestisce il salvataggio del valore di ritorno e l'esecuzione

– del sottoprogramma;

Il chiamato (CALLEE) gestisce l'allocazione delle variabili locali e del valore di

– ritorno.

Purtroppo il modello di chiamata a sottoprogramma non è identico in tutti i processori. Nel

caso del MIPS che analizzeremo per esempio le variabili possono essere salvate nei

registri o nello stack.

CHIAMATA A SOTTOPROGRAMMA

jal LABEL # $ra ← PC attuale

# PC ← indirizzo LABEL

RITORNO DA SOTTOPROGRAMMA

jr $ra # PC ← $ra

PASSAGGIO DEI PARAMETRI

I primi quattro parametri vanno inseriti nei registri del blocco a0-a3 (gli array sono

– puntatori al primo elemento);

Eventuali parametri in più vanno impilati sullo stack.

VALORE DI RITORNO

Viene salvato nel registro v0;

– Per il tipo double viene utilizzato anche il registro v1.

CONVENZIONI NEL SALVATAGGIO DEI REGISTRI

Salvati dal chiamante Salvati dal chiamato

t0-t9 s0-s7

Temporanei Variabili

a0-a3 fp

Argomento Frame Pointer

v0-v1 ra

Valore di ritorno Return Address

GESTIONE DELLO STACK

Purtroppo il MIPS non ha le istruzioni belle comode push e pop come l'x86. Devi fare te

da solo, ricordandoti che lo stack cresce da indirizzi più alti a indirizzi più bassi.

L'operazione di push si ottiene decrementando lo stack pointer e inserendo il dato co sw.

addi $sp, $sp, -4

sw $s0, 0($sp)

L'operazione di pop si ottiene prelevando il dato con lw e incrementando lo stack pointer.

lw $s0, 0($sp)

addi $sp, $sp, 4

La chiamata a funzione comporta:

Prologo del chiamante

– Salto al chiamato

– Prologo del chiamato

– Esecuzione del sottoprogramma

– Epilogo del chiamato

– Ritorno al chiamante

– Epilogo del chiamante

Convenzioni importanti:

Il prologo del chiamante corrisponde al caricamento dei parametri e al salvataggio

– dei registri;

Il prologo del chiamato corrisponde al salvataggio di registri e all'allocazione di

– variabili locali (quest'area è detta FRAME di attivazione della funzione);

Il salvataggio dei registri avviene seguendo l'ordine crescente dei numeri all'interno

– di ciascun gruppo;

Non si salvano registri laddove ciò è inutile: il fp si salva solo se è necessario

– referenziale dati nel frame di attivazione, il ra non si salva nelle funzioni foglia.

Ecco un'illustrazione più chiara di come può apparire lo stack durante una funzione:

t0-t7

a0-a3

v0-v1

arg5

arg6 ← Fine prologo del chiamante

fp precedente ← $fp

ra salvato

s0-s7

variabili locali ← Fine frame di attivazione

… ← $sp

CONVENZIONI CALLER

Prologo del chiamato

Inserisci in a0-a3 i parametri della funzione;

– Salva sullo stack i temporanei (ed eventualmente gli argomenti) che vuoi riavere

– inalterati al termine della funzione.

Salto al chiamato

jal FUNZIONE

CONVENZIONI CALLEE

Prologo del chiamato

Crea l'area di attivazione con un pushone (devi già sapere i byte che ti servono!);

– Se il fp è in uso il suo valore viene salvato per primo e il nuovo fp punterà a se

– stesso;

Se la funzione non è foglia ra viene salvato in modo da non essere sovrascritto (e

– quindi perduto) dalle chiamate successive;

Salva in pila i registri s0-s7 per le variabili locali.

Esecuzione del sottoprogramma

Epilogo del chiamato

Scrive in v0 il valore di ritorno;

– Ripristina i registri s0-s7 assegnati a variabili locali;

– Ripristina fp e ra se sono stati salvati;

– Elimina l'area di a

Dettagli
Publisher
A.A. 2016-2017
65 pagine
7 download
SSD Scienze matematiche e informatiche INF/01 Informatica

I contenuti di questa pagina costituiscono rielaborazioni personali del Publisher fiorixf2 di informazioni apprese con la frequenza delle lezioni di Architettura dei calcolatori e sistemi operativi e studio autonomo di eventuali libri di riferimento in preparazione dell'esame finale o della tesi. Non devono intendersi come materiale ufficiale dell'università Politecnico di Milano o del prof Negrini Roberto.