Le istruzioni: procedure e flusso di...

Post on 13-Jul-2020

0 views 0 download

Transcript of Le istruzioni: procedure e flusso di...

Le istruzioni: procedure e flusso di sviluppo

Luigi  Palopoli  

Procedure

•  L’u,lita’  di  un  computer  sarebbe  molto  limitata  se  non  si  potessero  chiamare  procedure  (o  funzioni)  

•  Possiamo  pensare  a  una  procedure  come  a  una  “spia”  che  fa  del  lavoro  per  noi  senza  che  noi  vogliamo  sapere  come  lo  fa  

•  La  cosa  importante  e’  di  me>ersi  d’accordo  su  un  protocollo  

Procedure

•  L’u,lita’  di  un  compute  sarebbe  molto  limitata  se  non  si  potessero  chiamare  procedure  (o  funzioni)  

•  Possiamo  pensare  a  una  procedure  come  a  una  “spia”  che  fa  del  lavoro  per  noi  senza  che  noi  vogliamo  sapere  come  lo  fa  

•  La  cosa  importante  e’  di  me>ersi  d’accordo  su  un  protocollo  

Protocollo

1.  me>er  i  parametri  in  un  posto  noto  2.  trasferire  il  controllo  alla  procedura  

1.  Acquisire  le  risorse  necessarie  2.  Eseguire  il  compito  3.  me>ere  i  valori  di  ritorno  in  pos,  no,  4.  Res,tuire  il  controllo  al  chiamante  

3.  Prendersi  il  valore  di  ritorno  e  “cancellare”  le  traccie  

Protocollo

•  Il  modo  in  cui  questo  protocollo  viene  messo  in  pra,ca  dipende  dall’archite>ura  e  dalle  convenzioni  di  chiamata  del  compilatore  

•  Ci  limi,amo  a  pochi  cenni  per  il  MIPS  

Protocollo di chiamata MIPS

•  L’idea  di  base  e’  di  cercare  di  laddove  possibile  i  registri,  perche’  sono  il  meccanismo  piu’  veloce  per  effe>uare  il  passaggio  dei  parametri  

•  Convenzione  per  il  MIPS  §  $a0,  ..$a3:  usa,  per  i  parametri  in  ingresso  §  $v0,  $v1    :  valori  di  ritorno  §  $ra                      :  indirizzo  di  ritorno  per  tornare  al  punto  di  partenza    

 

Protocollo di chiamata MIPS

•  Oltre  ai  registri,  l’hardware  MIPS  me>e  a  disposizione  l’istruzione  di  jump  and  link  (JAL)  che  effe>ua  il  salto  e  contemporaneamente  memorizza  in  ra  l’indirizzo  di  ritorno  §  L’indirizzo  che  viene  salvato  in  ra  e’  il  PC  (program  counter)  incrementato  di  4  (istruzione  sucessiva  alla  jal)  

•  Alla  fine  della  procedura  sara’  sufficiente  fare  un  salto        

 jr $ra!

!!

…e se i registri non bastano?

•  In  cer,  casi  I  registri  non  bastano  perche’  ho  piu’  parametri  di  quan,  ne  possano  contenere  I  registri    

•  In  tal  caso  si  una  lo  stack,  una  stru>ura  da,  ges,ta  con  disciplina  FIFO  in  cui  e’  possibile  me>ere  a  par,re  da  una  posizione  nota  alla  procedura  (puntata  dal  registro  fp)  I  parametri  in  piu’  

•  Lo  stack  si  puo’  usare  anche  me>ere  variabili  locali  (tramite  un’operazione  di  push)  e  salvare  registri  che  occorrera’  ripris,nare  in  seguito  

•  Alla  fine  della  procedura  si  puo’  ripulire  lo  stack  (operazione  pop)  riportandolo  alla  situazione  precedente  

Esempio

•  Consideriamo  la  procedura  in  C:  

int esempio_foglia(int g, int h, int i, int j) {! int f;!! f = (g+h) – (i+j);! return f;!}!

•  Cerchiamo  di  capire  come  verrebbe  trado>a  

Prologo

•  Per  prima  cosa  il  compilatore  sceglie  un’e,che>a  associata  all’indirizzo  di  entrata  della  procedura  (esempio_foglia)  §  In  fase  di  collegamento  (linking)  l’e,che>a  sara’  collegata  a  un’indirizzo  

•  La  prima  operazione  e’  quella  di  salvare  in  memoria  tuZ  I  registri  che  la  procedura  usa  in  modo  da  poterli  ripris,nare  in  seguito  

•  Tale  fase  e’  chiamata  prologo  e  potrebbe  richiedere  di  allocare  nello  stack  anche  spazio  per  le  variabili  locali  (se  i  registri  non  bastano).  

Prologo •  La  procedura  us  I  registri  s0,  t0,  t1;    •  Il  registro  SP  punta  alla  testa  dello  stack  (che  si  evolve  verso  il  basso)  •  Il  codice  del  prologo  e’  il  seguente:  

esempio_foglia: addi $sp, $sp, -12;!! ! ! ! !sw $t1, 8($sp)!! ! ! ! !sw $t0, 4($sp)!! ! ! ! !sw $s0, 0($sp)!

Decremen,amo  sp  di  12,  per  far  posto  a  3  

word    

Salvataggio  di  t1  in  sp+8  

Salvataggio  di  s0  in  sp+0  

Esecuzione della procedura

•  Dopo  il  prologo,  l’esecuzione  della  procedura:  

add $t0, $a0, $a1!add $t1, $a2, $a3!sub $s0, $t0, $t1!

In  t0  meZamo  g+h  

In  t1  meZamo  i+j  

In  s0  (g+h)-­‐(i+j)  

Epilogo

•  Dopo  aver  eseguito  la  procedura,  si  ripris,nano  i  registri  usa,  e  si  se>a  il  valore  di  ritorno  

add $v0, $s0, $zer0 !lw $s0, 0($sp)!lw $t0, 4($sp)!lw $t1, 8($sp)!addi $sp, $sp, 12!jr $ra!!

Trasferiamo  s0  in  v0  (valore  di  ritorno)  

Ripris,no  I  registri  prelevando  i  valori  

esa>amente  da  dove  li  avevo  messi  

Ripris,no  lo  stack  (tu>o  cio’  che  e’  so>o  sp  non  e’  significa,vo)  

Salto  al  punto  da  dove  sono  arrivato  

Evoluzione dello stack

Stack  prima  della  chiamata  

Stack  durante  l’esecuzione  della  

procedura  

Stack  dopo  la  chiamata  

Ulteriori complicazioni

•  In  realta’  le  cose  possono  complicarsi  per  via  di  §  Variabili  locali  §  Procedure  annidate  

•  Questo  si  risolve  usando  sempre  lo  stack  e  allocandovi  dentro  variabili  locali  e  valori  del  registro  ra  

•  Vediamo  un  esempio  

Procedure ricorsiva

•  Qui  (ma  sarebbe  lo  stesso  con  una  qualsiasi  funzione  che  chiama  un’altra  funzione)  abbiamo  due  problemi:  §  sovrascri>ura  di  $ra  che  mi  renderebbe  impossibile  il  ritorno  una  volta  finita  la  chiamata  innestata.  

§  Sovrascri>ura  di  $a0  usato  per  il  registro  n  

int fact(int n) {! if (n < 1) !

!return 1;! else!

!return n*fact(n-1);!}!

•  Consideriamo  il  seguente  esempio  

Procedure ricorsiva

Fact:!!addi $sp, $sp, -8 #Ci serve spazio per due oggetti!!sw $ra, 4($sp) #Salviamo ra!!sw $a0, 0($sp) #Salviamo a0!

•  Soluzione:  salvaguardare  il  registro  $ra,  a0  •  Vediamo  la  soluzione  •  Primo  step:  creiamo  spazio  nello  stack  e  salviamo  ra  e  a0  

•  Secondo  step,  tes,amo  se  n  <1  (ritornando  1  in  caso  afferma,vo):    

!slti $t0, $a0, 1 #t0 settato a 1 se n < 1!!beq $t0, $zero, L1 #Se n > 1 saltiamo a L1!

Procedure ricorsiva

•  Se  n  <=  1  chiudiamo  la  procedura        nota  che  non  ripris,niamo  ra  e  a0  (come  si  farebbe  normalmente,  perchè  non  li  abbiamo  cambia,)  

•  Se  n  >  1  decremen,amo  n  e  richiamiamo  fact    

!addi $v0, $zero, 1 #metodo del MIP per mettere in v0 1!!addi $sp, $sp, 8 #Ripuliamo lo stack!!jr $ra #Ritorniamo all’indirizzo di ritorno!

L1:!addi $a0, $a0, -1 #decrementiamo n!!jal fact #chiamiamo fact(n-1)!

Procedure ricorsiva

•  A  questo  punto  ripris,niamo  a0  e  ra  e  ripuliamo  lo  stack    !lw $a0, 0($sp) #Ripristino a0!

!lw $ra, 4($sp) #Ripristino ra!!addi $sp, $sp, 8 #ripulisco stack!

•  Non  ci  resta  che  mol,plicare  fact(n-­‐1),  che  è  in  v0,  per  n  e  ritornare  

!mul $v0, a0, $v0!!jr $ra!

Storage class

•  Le  variabili  in  C  sono  in  genere  associate  a  locazioni  di  memoria  

•  Si  cara>erizzano  per  §  Tipo  (int,  char,  float)  §  Storage  class  

•  Il  C  ha  due  possibili  storage  class  §  Automa,c  (variabili  locali  che  hanno  un  ciclo  di  vita  collegata  alla  funzione)  

§  Sta,c  sopravvivono  alle  chiamate  di  procedura.  Sono  essenzialmente  variabili  globali  o  definite  dentro  funzioni  come  sta,c  

•  Le  variabili  sta,che  sono  memorizzate  in  una  zona  di  memoria  (nel  MIPS  accessibile  a>raverso  il  registro  global  pointer,  $GP)  

Variabili locali

•  L’ul,mo  problema  è  cos,tuito  dalle  variabili  locali  

•  Quando  sono  poche,  si  riescono  a  usare  registri  

•  Quando  sono  tante  (ad  esempio  struct  complesse  o  array)  non  ci  sono  abbastanza  registri    

•  Quello  che  si  fa  è  allocare  le  variabili  locali  nello  stack  

Record di attivazione

•  Il  segmento  di  stack  che  con,ene  registri  salva,  e  variabili  locali  rela,ve  a  una  funzione  viene  chimata  record  di  aZvazione  (o  procedure  frame)  

•  Le  variabili  locali  vengono  individuate  tramite  un  offset  a  par,re  da  un  puntatore  

•  Il  puntatore  $sp  è  alle  volte  scomodo  come  base  perchè  cambia  durante  l’esecuzione  della  funzione  

•  Il  registro  $fp  (frame  pointer)  viene  sempre  mantenuto  costante  durante  la  funzione  e  può  essere  usato  come  base.  

Evoluzione dello stack

$fp  

$sp   $fp  

$sp  

Saved  arguments  registers  

Saved  return  address  Saved  

registers  Saved  

registers  

$fp  

$sp  

Prima  della  chaimata  

Durante  la  chiamata  

Dopo  la  chiamata  

Dati dinamici

•  In  aggiunta  a  variabili  globali  e  variabili  locali  abbiamo  anche  le  variabili  dinamiche  (quelle  che  vengono  allocata  con  malloc/free,  new/delete)  

•  Il  MIPS  ado>a  il  seguente  schema  di  memoria    

Resrved  

Text  

Sta,c  Data  

stack  

Dynamic  data  

$sp  

$gp  

$pc  

Lo  stack  procede  per  indirizzi  decrescen,  

Lo  heapprocede  per  indirizzi  crescen,  

Convenzioni sui registi •  In  base  alle  convenzioni,  l’uso  dei  registri  è  nella  sequente  tabella  

Nome   Numero   Uso   Preservare  

$zero   0   Valore  costante  0   n.a.  

$v0  -­‐  $v1   2-­‐3   Valori  di  ritorno  per  chiamate  di  funzioni  e  valuazione  di  espressioni  

No  

$a0-­‐$a3   4-­‐7   Argomen,     No  

$t0-­‐$t7   8-­‐15   Temporanei   No  

$s0  -­‐  $s7   16-­‐23   Salva,   Si  

$t8-­‐$t9   24-­‐25   Ulteriori  temporanei   No  

$gp   28   Puntatore  ai  globali   Si  

$sp   29   Putnatore  allo  stack   Si  

$fp   30   Frame  pointer   Si  

$ra   31   Return  Address   si  

Elaborazione

•  Per  quanto  le  ricorsioni  siano  elegan,  spesso  sono  causa  di  varie  inefficienze  

int sum(int n) {! if (n > 0) !

!return sum(n-1) + n;! else!

!return n;!}!

Never  hire  a  programmer  who  solve  the  factorial  with  a  recursion  

•  Consideriamo  la  seguente  funzione  

Elaborazione

•  Consideriamo  la  chiamata  sum  (2)  

Sum  (2)  

n  =  2  

Sum  (1)  

n  =  1  

Sum  (0)  

n  =  0  

2+sum(1)  

1+sum(0)  0  

1+0  

2+1  

Il  valore  di  ritorno  viene  costruito  Tornando  su  per  la  catena  di  chiamate.  Ogni  frame  di  aZvazione  deve  essere    Preservato  per  produrre  il  risutlato    

corre>o.  

Elaborazione

•  Consideriamo  ora  il  codice  così  modicato  

int sum(int n, int acc) {! if (n > 0) !

!return sum(n-1, acc+n);! else!

!return acc;!}!

•  Stavolta  la  chiamata  ricorsiva  è  l’ul,ma  cosa  che  la  funzione  fa  (si  limita  a  ritornare).    

•  Questa  ricorsione  viene  de>a  di  coda…ritorniamo  al  nostro  esempi  sum(2,0).  

Elaborazione

•  Consideriamo  la  chiamata  sum  (2)  

Sum  (2,0)  

n  =  2,  acc=0  

Sum  (1)  

n  =  1,  acc=  2  

Sum  (0)  

Sum(1,2)  

Sum(0,  3)  3  

3  

3  

n  =  0,  acc=  3  

In  questo  caso  lungo  I  rami  di  ro,orno  non  faccio  

Che  res,tuire  3.  Conservare  I  da,  nello  stack  

Di  aZvazione  è  inu,le.  Posso  usare  Un  unico  stack  di  aZvazione  e  svlogere  

La  ricorsione  in  itnerazione.    

Ottimizzazione

•  Alcuni  compilatori  riconoscono,  e  possono  oZmizzare  come  segue  (assumiamo  a0  =  n,  a1=acc)  

Sum: !slti $t0, $a0, 1 #t0=1 se a0 <= 0!! !bne $t0, $zero, sum_exit #se n <= 0 vai a sum_exit !! !add $a1, $a1, $a0 #somma n ad acc!! !addi $a0, $a0, -1 #sottrai 1 da n!! !j sum!

Sum_exit:!! !add $v0, $a1, $zer0! ! ! !#inderisci acc in v0!! !jr $ra!

•  Certo  se  se  ne  rende  conto  il  programmatore  e  lo  fa  dire>amente  è  meglio  :=)    

Comunicare

•  Fino  ad  ora  abbiamo  visto  come  un  computer  si  può  usare  per  fare  con,  

•  In  realtà  altre>anto  importante  è  la  capacità  per  un  computer  di  comunicare  tramite  tes,  

•  Questo  può  essere  fa>o  codificando  i  cara>eri  con  sequenze  di  bit  

Comunicare

•  Fino  ad  ora  abbiamo  visto  come  un  computer  si  può  usare  per  fare  con,  

•  In  realtà  altre>anto  importante  è  la  capacità  per  un  computer  di  comunicare  tramite  tes,  

•  Questo  può  essere  fa>o  codificando  i  cara>eri  con  sequenze  di  bit  

Codifica ASCII

•  Una  delle  codifiche  più  famose  e  usate  e  quella  ASCII  (su  7  bit)  

Istuzioni per caricare e scaricare byte

•  Il  fa>o  che  la  codifica  ASCII  sia  così  popolare  obbliga  in  sostanza  ad  avere  istruzioni  di  trasferimento  che  operano  sul  byte  

!lb $t0, 0($sp) #legge un byte dalla cima dello stack !! ! ! ! ! #e lo inserisce nei bit meno significativi!! ! ! ! ! # di t0!!sb $t0, 0($gp) # inserisci gli otto bit meno significativi!! ! ! ! ! #di to in $gp !

Esempio

•  In  C  una  stringa  è  un  array  di  byte  terminata  dal  cara>ere  0  

•  Consideriamo  il  seguente  programma  C    

void strcpy(char * x, char * y) {!!int i;!

!!i=0;!!while((x[i]=y[i])!=‘\0’)!! !i+= 1;!

}!!

Esempio

•  Vediamo  la  traduzione  in  assembler  MIPS  •  Prima  cosa  salviamo  nello  stack  s0  in  cui  me>eremo  i  

 Strcpy: !!addi $sp, $sp, -4 #creiamo nello stack spazio per a0!!sw ! ! $s0, 0($sp) #salviamo s0!

!

•  A  questo  punto  seZamo  i  a  0    addi $s0, $zero, $zero #i = 0+0!!

Esempio

•  Step  successivo  meZamo  in  t1  l’indirizzo  di  y[i]  (label  con  inizio  del  loop)      Contrariamente  ai  preceden,  esempi  sugli  array,  qui  non  abbiamo  bisogno  di  mol,plicare  per  4  perchè  l’accesso  è  al  singolo  byte  

L1: add $t1, $s0, $a1 #indirizzo di y[i] in t1 !!

Esempio

•  A  questo  punto  inseriamo  il  cara>ere  puntato  da  y[i]  in  t2      Notare  che  il  cara>ere  è  un  unsigned  byte  

•  Memorizziamo  y[i]  in  x[i]      usciamo  dal  loop  se  y[i]  è  0  

lbu $t2, 0($t1) #t2 = y[i] !!

add $t3, $s0, $a0 #indirizzo di x[i] in t1 !sb $t2, 0($t3) #x[i]=y[i]!

beq $t2, $zero, L2 #se y[i]==0 vai a L2!

Esempio

•  In  caso  nega,vo  chiudo  il  loop  incrementando  i      

•  Uscita  dalla  procedura  con  rispris,no  di  s0,  rimozione  dallo  stack  e  ritorno    

addi $s0, $s0, 1 #i = i +1 !j L1 #Salta a L1!

L2: lw $s0, 0($sp) #ripristino s0!!addi $sb, $sp, 4 #ripulitura dello stack!!jr $ra #ritorno!

E che ne è delle lettere accentate?

•  Ascii  va  bene  solo  per  l’alfabeto  inglese  •  Esiste  una  codifica  che  usa  16  bit  ed  è  ado>ata  in  Java  che  si  chiama  unicode.  

•  La  codifica  unicode  è  suddivisa  in  blocchi.    •  Ciascun  blocco  con,ene  un  numero  di  cara>eri  pari  a  un  mul,plo  di  16  §  Es  le>ere  greche  partono  da  X0370,  quelle  cirilliche  da  X0400  

Blocchi Unicode

Caricamento di mezza parola

•  Per  supportare  ques,  ,pi  di  da,  a  16  bit,  l’assembler  MIPS  me>e  a  disposizione  la  possibilità  di  caricare/scaricare  anche  metà  parola  (I  16  bit  meno  significa,vi)  in  e  da  un  registro  

lhu $t0, 0($sp) #legge mezza parola (unsigned)!Sh $t0, 0($gp) #memorizza mezza parola (Signed)!

Riepilogo sulle modalià di indirizzamnto

Operandi  Costan,,  caricamento/scaricamento  

Operazioni  su  registri  

Salto  condizionato  

Salto  incodizionato  

Toolchain  

A.K.A. quella roba per passare da codice ad eseguibile  

Non parliamo la stessa lingua  

Quando programmiamo usiamo linguaggi che sono più vicini a noi che al PC.  

Imparare una lingua è difficile  

•  Per poter parlare come dei nativi è necessario lavorare molto, e col PC è uguale scrivere in Assembly in maniera intelligente richiede una quantità di esperienza impressionante.  

•  È per questo che scriviamo in un linguaggio vicino a noi e facciamo fare il lavoro ad un traduttore.  

Toolchains - Overview  

Toolchain - Compilatore  

Toolchain - Compilatore  

•  Trasforma i linguaggi di alto livello in linguaggio Assembly.  

•  Spesso il risultato è migliore che farselo a mano  

Toolchain - Assembler  

Toolchain - Assembler  

u  Traduce un codice sorgente in linguaggio Assembly in file oggetto  

u  I file oggetto sono sequenze di istruzioni in linguaggio macchina, dati ed altre informazioni necessari al caricamento in memoria di un programma  

Assembler: Pseudoistruzioni  

u  Gli assembler accettano anche istruzioni che non vengono supportate dal processore ma che sono più comode da leggere: le pseudoistruzioni  

u  Queste vengono lette e convertite in sequenze di istruzioni accettate dalla CPU (e.g. move $t0, $t1 → add $t1, $t0, $zero)  

Assembler: numeri  

• L’assembler accetta numeri espressi in basi differenti: binario, ottale, decimale ed esadecimale  

Assembler: segmenti  

•  Contiene gli indirizzi per tutti i simboli:  u  Object File Header  u  Text Segment  u  Data Segment  u  Relocation Information  

u  Symbol Table (simboli → indirizzo)  u  Debugging Information  

Esempio Nome  

Procedura  

Dimensioni  

Caricamento  di  una  variable  X  di  cui  non  si  sa  l’indirizzo  

Chiamata  di  una  procedura  di  cui  no  si  sa  ancora  

l’indirizzo  

Informazioni  per  il  linker  

Intestazione file oggetto

Nome Procedura A Dimensione .text 100hex Dimensione .data 20hex

.text Indirizzo Istruzione 0 lw $a0, 0($gp)

4 jal 0 ... ...

.data 0 (X) ... ... Informazioni di Rilocazione Indirizzo Tipo di Istruzione Dipendenza

0 lw X

4 jal B

Tabella dei simboli Etichetta Indirizzo X - B -

Esempio: altra procedura

Intestazione file oggetto

Nome Procedura B Dimensione .text 200hex Dimensione .data 30hex

.text Indirizzo Istruzione 0 sw $a1, 0($gp)

4 jal 0 ... ...

.data 0 (Y) ... ... Informazioni di Rilocazione Indirizzo Tipo di Istruzione Dipendenza

0 sw Y

4 jal A

Tabella dei simboli Etichetta Indirizzo Y -

A -

Toolchain: Linker  

Toolchain: Linker  

•  Prende i file oggetto assemblati in precedenza e li collega tra di loro, in modo da chiamare le procedure corrette nei vari file oggetto.  

•  Il risultato è un file eseguibile, che è un file oggetto senza riferimenti irrisolti.  

Toolchain: Linker  

•  Sono presenti tre simboli nei file oggetto:  u  Defined symbols, simboli che possono

venir chiamati da altri file oggetto  

u  Undefined symbols, chiamate ai moduli dove i simboli sono stati soddisfatti  

u  Local symbols, simboli utilizzati all’interno di un file oggetto per aiutare la rilocazione  

Linker: simboli  

Linker: passi di linking  

Il linking è formato da tre passi:  1.  Caricare temporanemente in memoria codice e moduli  2.  Determinare gli indirizzi dei dati e delle etichette  

3.  Correggere i riferimenti interni ed esterni  

Ritorniamo all’esempio  

Ritorniamo all’esempio dei due file oggetto, uno nel quale viene definita la funzione A ed uno nel quale viene definita B.  

Intestazione file oggetto

Nome Procedura A Dimensione .text 100hex Dimensione .data 20hex

.text Indirizzo Istruzione 0 lw $a0, 0($gp)

4 jal 0 ... ...

.data 0 (X) ... ... Informazioni di Rilocazione Indirizzo Tipo di Istruzione Dipendenza

0 lw X

4 jal B

Tabella dei simboli Etichetta Indirizzo X - B -

Intestazione file oggetto

Nome Procedura B Dimensione .text 200hex Dimensione .data 30hex

.text Indirizzo Istruzione 0 sw $a1, 0($gp)

4 jal 0 ... ...

.data 0 (Y) ... ... Informazioni di Rilocazione Indirizzo Tipo di Istruzione Dipendenza

0 sw Y

4 jal A

Tabella dei simboli Etichetta Indirizzo Y -

A -

Esempio di linking - cont.  

•  Sia A che B hanno riferimenti non risolti (A, B, vari displacements).  

•  Per risolverli vengono caricati in memoria i files, usando le convenzioni del MIPS e poi vengono inseriti i riferimenti corretti.  

Allocazione memoria in MIPS  

Il segmento testo parte da 0x0040 0000  

I dati statici vengono caricati da 0x1000 0000, $gp viene usato per l’accesso applicando un displacement signed a 16 bit.  

Primo passo: Caricare in memoria  

•  Il segmento .text, in memoria, viene caricato a partire da 0x0040 0000, mentre .data a partire da 0x1000 0000.  

•  Usando le informazioni nei file headers si può sapere dove finiranno i segmenti .text e .data dei due file oggetto.  

Primo passo: Caricare in memoria  

Dimensione .text 300hex

Dimensione .data 50hex .text Indirizzo Istruzione 0040 0000hex lw $a0, 0($gp) [X]

0040 0004hex jal 0 [Procedure B]

... ...

0040 0100hex sw $a1, 0($gp) [Y]

0040 0104hex jal 0 [Procedure A]

... ...

.data Indirizzo 1000 0000hex (X)

... ...

1000 0020hex (Y)

... ...

Secondo passo: Risolvere gli indirizzi  

u  Le jump (jal) sono facili: basta recuperare l’indirizzo della prima istruzione della procedura ed usare quello  

u  I trasferimenti (lw, sw) richiedono di calcolare il displacement rispetto a $gp. Questo displacement è un signed a 16bit e si parte da 0x10008000.  

Intestazione file eseguibile

Dimensione .text 300hex

Dimensione .data 50hex .text Indirizzo Istruzione 0040 0000hex lw $a0, 0x8000($gp) 0040 0004hex jal 0x40 0100 ... ... 0040 0100hex sw $a1, 0x8020($gp) 0040 0104hex jal 0x40 0000 ... ... .data Indirizzo 1000 0000hex (X)

... ...

1000 0020hex (Y)

... ...

Loader  

Il loader è una procedura o un programma che carica un programma in memoria e lo esegue  

Loader  

Loader: Passaggi  1. Validazione (e.g. permessi, memoria disponibile)  2. Copia del programma in memoria  

3. Copia degli argomenti nello stack  

4. Inizializzazione dei registri  5. Salto all’entry point (i.e. _start)  

Libreria  

•  Una libreria è una collezione di file .o e di header file (con le signature delle procedure)

•  Per le librerie ci sono due modalità •  Statica •  Dinamica

•  Se si usa il linking statico il liniker valuta tutti i file oggetto della libreria “toccati” da una chiamata del modulo e collega I relativi moduli

•  Vantaggi: •  Codiv

Linking statico  

•  Se si usa il linking statico il liniker valuta tutti i file oggetto della libreria “toccati” da una chiamata del modulo e collega I relativi moduli

•  Vantaggi: •  Codice autocontenuto

•  Svantaggi: •  Potenziali dimensioni eseguibile

•  Usare moduli piccoli e con piccole interfaccie •  Necessità di ricompilare il tutto se si cambia

codice o libreria

Dynamic Linking  

L’idea del dynamic linking è di spostare il linking al tempo di caricamento •  Quando il programma viene caricato, a quel

punto vengono prelevate I vari moduli di libreria dal file system e viene creato l’eseguibile

•  Vantaggi •  Ridurre le dimensioni dell’eseguibile •  Condividere lo stesso codice di libreria tra più

processi. •  Volendo, si può effettuare una “lazy

relocation”: •  Inserire una chiamata a una prcedura dummy per ogni chiamta

di libreria che punta al dynamic linking  

Dynamic Linking  

•  Volendo, si può effettuare una “lazy relocation”:

•  Inserire una chiamata a una prcedura dummy per ogni chiamata di libreria che punta al dynamic linker

•  Alla prima chiamata viene risolto l’indirizzo e di lì in poi si usa