L’assembler INTEL IA32
Luigi Palopoli Istruzioni e operandi
•  Contrariamente all’assembler del MIPS nel caso dell’IA32 ci possono essere due o tre operandi anche per le istruzioni logico aritme>ca •  Inoltre esistono istruzioni ad un operando   ES: INC (INCREMENTA) •  Nella sintassi AT&T che useremo noi l’operando des>nazione si scrive sempre in fondo (contrariamente a quanto abbiamo visto per il MIPS) •  Per alcune istruzioni si da per implicito che l’operando e’ un par>colare registro (deJo accumulatore). Intel
•  Nell'assembler Intel (sintassi AT&T) si usa dis>nguere anche se l'istruzione opera su byte (b), su word a 16bit (w) o su word a 32 bit (l) e si usa % prima di ogni registro   Es.  movb %Ax, Dest (opera sul byte)  movl %EAX, Dest (opera su word) •  Come accumulatore viene spesso usato EAX (32bit)   E' possibile usarne solo 16bit specificando AX:   AX a sua volta può essere par>zionato   AL (8 bit meno significa>vi)   AH (8 bit più significa>vi) Esecuzione delle Istruzioni
•  Gli elaboratori sono macchine sequenziali •  L’esecuzione “naturale” delle istruzioni è “una-­‐dopo-­‐
l’altra” •  Un programma viene caricato nel processore una istruzione alla volta nell’IR •  Il processore esegue l’istruzione e poi carica la successiva a cui punta il PC •  La fase iniziale si chiama “instruc>on fetch” (o load, o caricamento) •  La seconda fase di chiama “instruc>on execu>on” (o esecuzione) Intel
Inizio esecuzione Address Contents i Movl A,%EAX i + 4 Add B,%EAX i + 8 Movl %EAX ,C 3-­‐instruc>on program segment In IA32 l’esecuzione viene
sempre assunta sequenziale
A B C Data for the program Come per il MIPS esiste la
possibilita’ di fare salti
condizionati e incondizionati
Metodi di indirizzamento
•  Una forte differenza con il MIPS e’ nella modalita’ di indirizzamento (come si specificano gli operandi di un’istruzione)   Per il MIPS abbiamo visto si opera solo tra registri, o si possono trasferire da> da/a memoria a/da un registro   Inoltre alcune istruzioni si possono eseguire in modalita’ immediata (con alcuni operandi costan>) •  Per l’intel abbiamo gli operandi possono essere   Costan> (modalita’ immediata)   Registri (modalita’ registro)   Indirizzi •  Contrariamente al MIPS gli indirizzi di memoria possono essere specifica> in varie modalita’ diverse. Indirizzamento in modo registro
•  In assembler INTEL questo indirizzamento è presente •  Es. Movl %eax, %ebp
•  Notare che in MIPS una cosa del genere si farebbe cosi’: add $ebp, $eax, $zero
•  I registri principali per uso generale sono: eax, ebx, ecx, edx, esi, edi, ebp
Nel MIPS I registri sono mol> di piu’. Registri IA32
Registri IA32
•  EAX, EBX, ECX, EDX: general purpose   EAX: accumulatore   EBX: puntatore a memoria   ECX: controllo cicli   EDX: estende EAX per operazioni a 64bit • 
• 
• 
• 
• 
• 
ESI, EDI: puntatori a stringhe EBP: puntatore alla testa del frame di afvazione ESP: puntatore alla testa della pila EIP: instruc>on pointer CS, ..., GS: seleJori di segmento EAFLAGS: registro con i flag di stato Indirizzamento immediato
•  Per l'Intel (sintassi AT&T), il valore della costante è in preceduto da un $ •  Es. Move $1, %EAX
Add $2, %EAX
Indirizzamento in memoria
•  Nell'architeJura intel tuJe le modalità di indirizzamento sono casi par>colare di un modo generale:   ind = base + (index*scale)+displacement dove  base è uno dei registri eax, ebx, ecx, edx, esp, ebp, esi e edi
  index può essere uno dei precedenti (eccetto esp)
  scale può essere (1, 2, 4, o 8)   displacement è un valore immediato a 8, 16 o 32 bit
•  Per il MIPS abbiamo solo base e displacement
•  Ad esempio
  movl 10(%ebx,%ecx,2), %eax
porta in eax il contenuto di memoria in
ebx+2*ecx+10
Esempi di indirizzamento
Salti e cicli
•  Consideriamo il problema di sommare N numeri •  Richiede (ad esempio) l’uso di un modo indirizzamento indireJo (>po puntatore), in cui un registro viene aggiornato ad ogni ciclo per contenere l’indirizzo della locazione di memoria in cui si trova di volta in volta l’operando Intel
Address LOOP Contents movl movl 0,%ecx $0, %eax Addl Addl cmpl JNE Move a(,%edx,4),%eax $1,%edx %edx, $N LOOP %eax,SUM Ini>aliza>on Uso dell’indirizzamento
indiretto e indicizzato
•  L’indirizzamento indicizzato è fondamentale nella ges>one delle struJure da> complesse •  Immaginiamo di voler ges>re i vo> di tuf gli studen> di un corso, che effeJuano 3 test, ad esempio per calcolare la media (o semplicemente la somma complessiva) dei vo> assegna> durante i test Esempio
N LIST n Student ID LIST + 4 Test 1 LIST + 8 Test 2 LIST + 12 Test 3 LIST + 16 Student ID Test 1 Test 2 Test 3 •
•
•
Student 1 Student 2 Formato assembler
•  Per operare correJamente bisogna definire un formato univoco del linguaggio assembler   e>cheJe (label), possono avere un nome logico oltre al valore numerico   istruzione (opera>on – instruc>on)   operandi (operands)   commen> (comments) label
i-code
op1,op2,op3
bla,bla,bla,...
Sintassi gcc per Intel
•  Somma di 2 numeri ... .pippo:
movl
$27,%eax
/*loads the number 27
in the accumulator*/
addl
A,%eax
/*adds the content of
memory location “A” in
the accumulator*/
movl
%eax,B
/*store the result into
B*/
Qualche altra istruzione assembler ...
•  Istruzioni logiche sui singoli bit di una parola not
dst
bitwise complement “dst”, that may be a
register or a memory location (mloc)
and
dst1,dst2
bitwise “ANDs” the content of dst1/2, that
may be registers, mlocs or constants
or
dst1,dst2
bitwise “ORs” the content of dst1/2, that
may be registers, mlocs or constants
cmp
dst1,dst2
compares the content of dst1/2, that
may be registers, mlocs or constants,
returns “0” if dst1=dst2
Qualche altra istruzione assembler ...
•  Istruzioni algebriche neg
dst
trasforma “dst” in “–dst”
mul
dst1,dst2, calcola la moltiplicazione tra dst1/2
supposti numeri interi, e memorizza il
risultato in dst2, il cui contenuto viene
distrutto; resta il problema che il risultato
può andare in overflow, problema peraltro
comune anche ad Add
•  Nell’architettura INTEL esistono anche una seri di istruzioni
per gestire direttamente il floating point
Intel
•  Istruzioni di Shio logiche shll
$N,%dst
sposta il contenuto del registro dst a sinistra
di N passi, N può usare un sistema di
indirizzamento qualsiasi; i bit che escono dal
registro sono persi, le posizioni a destra sono
rimpiazzate da “0” (operandi a 32bit)
shrl
$N,%dst
sposta il contenuto del registro Ri a destra di
N passi, N può usare un sistema di
indirizzamento qualsiasi; i bit che escono dal
registro sono persi, le posizioni a sinistra
sono rimpiazzate da “0” (operandi a 32bit)
Intel
•  Istruzioni di Shio aritme>che (mol>plicazione/
divisione per due) sall
$N,%dest sposta il contenuto del registro dest a
sinistra di N passi, N può usare un
sistema di indirizzamento qualsiasi; i bit
che escono dal registro sono persi, le
posizioni a destra sono rimpiazzate da
“0” (identica a LShfL)
sarl
$N,%dest sposta il contenuto del registrodest a
destra di N passi, N può usare un sistema
di indirizzamento qualsiasi; i bit che
escono dal registro sono persi, le posizioni
a sinistra sono rimpiazzate da bit uguali al
bit di segno
shll
C before: 0 aoer: 1 R0 0 1 1 1 0 1 1 0 . . . . . . (a) Logical/Aritmetical shift
left
0 0 1 1 0 1 1 0 0 LShiftL
#2,R0
shrl
0 before: aoer: R0 0 1 1 1 0 . . C . 0 1 1 0 0 0 1 1 1 0 . . (b) Logical shift right
. 0 0 1 LShiftR #2,R0
sarl
R0 before: aoer: 1 0 0 1 1 C . . . 1 1 1 0 0 1 1 (c) Arithmetic shift right
0 1 0 . . . 0 0 1 AShiftR #2,R0
Intel
•  Istruzioni di rotazione roll
$N,%dst
sposta ciclicamente il contenuto del
registro dst a sinistra di N passi, N può
usare un sistema di indirizzamento
qualsiasi;
rcll
$N,%dst
come RotL, ma include il bit di carry
ror
$N,%dst
come RotL, ma verso destra
rcr
$N,%dst
come RotR, ma include il bit di carry
roll
R0 C before: 0 aoer: 1 0 1 1 1 0 1 1 0 . . . . . . (a) Rotate left without
carry
0 1 1 0 1 1 0 1 RotateL
#2,R0
rcll
R0 C before: 0 0 1 1 1 0 aoer: 1 1 1 0 (b) Rotate left with
carry
. . . . . . 0 1 1 0 1 1 0 0 RotateLC #2,R0
ror
R0 before: aoer: 0 1 1 1 0 . . 1 1 0 1 1 1 0 (c) Rotate right without carry
C . 0 1 1 . . . 0 RotateR #2,R0
0 1 Qualche altra istruzione assembler ...
•  Istruzioni di fine ret:
comunica al sistema operativo (o a un
altro programma, o al programma
principale se stiamo considerando una
subroutine) che il programma ha terminato
l’esecuzione
Esecuzione dei programmi
•  l’Assembler NON è il linguaggio macchina •  Assemblatore: traduce l’assembler in linguaggio macchina, risolvendo eventuali “conflif” (es. sal> in avan>)   simile a un compilatore •  Loader: carica un programma in memoria (ad esempio dal disco rigido) al momento dell’esecuzione, risolvendo gli indirizzi rela>vi e controllando che ci siano tuf i “pezzi” necessari all’esecuzione correJa Funzioni fondamentali di I/O
•  Qualsiasi elaboratore deve poter comunicare con l’esterno ... almeno tramite una tas>era e un video/stampante Bus Processor DATAIN SIN Keyboard DATAOUT SOUT Display tastiera video e processore sono collegati al bus
Funzioni fondamentali di I/O
•  è uso che il processore “veda” i registri periferici di interfaccia di tas>era e video come delle normali posizioni di memoria (memory mapped I/
O)   DATAIN registro di ingresso   DATAOUT registro di uscita •  I/O sono molto più len> del processore •  Quando sono disponibili i da> su DATAIN? •  Quando sono sta> lef i da> da DATAOUT? INTEL
•  Il processore deve poter aspeJare che l’I/O sia abilitato, quindi deve avere un “loop” per leggere il registro solo al momento opportuno READW
test
$3, SIN
controlla lo stato dell’ingresso
jnc
READW
continua il loop se il dato non è
disponibile
movb
Din,%al
legge il dato
WRITEW test
$3, SOUT
controlla lo stato dell’uscita
jnc
WRITEW
continua il loop se il display
non può ricevere il dato
movb
%al, Dout
scrive il dato
Un programma per fare l’eco di caratteri ... fino a CR(IA32)!
.BEGIN
lea
loc,%ebp
/*Carica l'indirizzo loc in ebp*/
.READ
testb
jnc
movb
movb
inc
$3, SIN
READ
DATAIN,AL
AL,(%ebp)
%ebp
/*controlla lo stato dell’ingresso*/
/memorizza il dato */
testb
$3, SOUT
controlla lo stato dell’uscita
jnc
ECHO
continua il loop se il display non
può ricevere il dato
movb
%al, DATAOUT
scrive il dato, facendo l’eco e
resetta SOUT
cmpb
$32, al
punta alla nuova locazione di
memoria
jne
READ
passa a leggere un altro carattere
.ECHO
Subroutines e gestione della
memoria
•  I programmi sono (auspicabilmente!!) compos> di tante subrou>ne •  Il programma principale invoca una subrou>ne, che ne invoca un altra, che ne invoca una successiva ... •  Come evolve il program counter? •  Come viene mantenuto lo stato del programma nel passaggio da una subrou>ne ad un’altra? Subroutines e gestione della
memoria
•  Come si ges>sce la memoria del processore per evitare conflif tra subrou>nes? •  Come si possono passare parametri e risulta> tra subrou>nes diverse? •  In par>colare come si passano tra una subrou>ne “chiamante” ed una “chiamata”? Tecniche di gestione della
memoria
•  Coda   spazio di memoria in cui gli elemen> che entrano per primi saranno anche i primi a uscire (FIFO – First In First Out)   Realizzabile in memoria tramite un buffer circolare ges>to da puntatori dinamici •  Stack   spazio di memoria in cui gli elemen> che entrano per primi gli ulKmi a uscire (LIFO – Last In First Out)   Realizzabile in memoria tramite un buffer circolare ges>to con un puntatore sta>co e uno dinamico Stack
•  Come la pila dei giornali in saloJo ... •  Un puntatore (fisso) segna il fondo della coda •  Un puntatore (mobile) segna l’ul>mo elemento entrato nello stack e anche il primo ad uscirne •  La ges>one di uno stack in memoria si può fare semplicemente con una locazione di memoria (in genere un registro specializzato) che svolge il ruolo di puntatore e delle operazioni di move per scrivere e leggere gli elemen> •  è u>le effeJuare dei controlli per evitare di leggere elemen> da uno stack vuoto o di riempire lo stack all’infinito Stack
•  ScriJura 0 Stack Pointer register SP •
•
•
-­‐ 28 17 Current top element •  LeJura 739 Stack BOTTOM •
•
•
43 •
•
•
add $-­‐4,%SP mov ITEM,(%SP) BoQom element mov (%SP),ITEM Add $4,SP Push e Pop
•  Le operazioni di leJura e scriJura in uno stack in genere si chiamano PUSH ITEM per la scriJura e POP ITEM per la leJura •  Le operazioni di push e pop sono normalmente realizzate con subrou>nes che controllano lo stato dello stack stesso Push e Pop
PUSH Cmp
JE
Add
Move
CIMA,%SP
controlla che SP non sia già posizionato alla
cima della memoria ammessa per lo stack
FULLERROR
$-4,%SP
ITEM,(%SP)
se è gia pieno salta a una routine di errore
Routine di PUSH con controllo dello riempimento
POP
CMP
FONDO,%SP
controlla che SP non sia già posizionato alla
fondo della memoria riservata allo stack
JE
Add
Move
EMPTYRROR
$4,%SP
(%SP),ITEM
se è gia pieno salta a una routine di errore
Routine di POP con controllo dello riempimento
Subroutines e Stack
•  Lo stack è la struJura usata abitualmente per il passaggio dei parametri e del controllo tra subrou>nes •  Consente in modo naturale la ricorsione e l’annidamento di subrou>nes senza nessun vincolo a priori sul livello di annidamento •  Noi daremo per scontato che esistono le rou>nes pop e push (con un solo parametro) e usiamo quelle per ges>re lo stack, ovviamente invocando POP e PUSH ... usiamo lo stack!! Salvataggio del PC
•  Passando il controllo del programma ad una subrou>ne bisogna salvare il Program Counter per sapere da dove riprendere l’esecuzione Memory locaKon Calling program 200 Call SUB 204 next instrucKon Memory locaKon 1000 SubrouKne SUB first instrucKon Return Salvataggio del PC
•  L’istruzione Call salva il PC nello stack del processore e poi esegue un branch incondizionato all’istruzione di inizio della subrou>ne •  Bisogna sempre ricordare che una subrou>ne in assembler non è nient’alto che una sequenza di istruzioni in un’area di memoria PUSH
%PC
salva il program counter
JMP
PIPPO
salta alla prima istruzione della subroutine
istruzioni equivalenti alla Call di una subroutine
Subroutines e parametri
•  Nei linguaggi di alto livello i parametri si passano ... tra parentesi call subr(par1,par2,par3) •  In assembler invocare una subrou>ne vuol dire solamente effeJuare un salto incondizionato a una locazione di memoria Call SUBR ↔ JMP SUBR •  I parametri che userà la subrou>ne devono già essere in una opportuna area di memoria ... in cima allo stack •  I parametri res>tui> dalla subrou>ne saranno anche loro passa> aJraverso lo stack Subroutines e parametri
•  Invocando una subrou>ne in un linguaggio di alto livello es: is_date(day,month,year) •  Si ofene una sequenza di istruzioni in assembler del >po Push PAR3 Push PAR2 Push PAR1 Call ISDATE •  Dove PAR1, PAR2 e PAR3 sono le locazioni di memoria in cui sono state memorizzate le variabili day, month e year Passaggio dei parametri
SP Return address (PC) PAR1 PAR2 PAR3 •  I parametri vengono scrif nello stack (ad esempio in ordine inverso) •  Per ul>mo viene salvato il PC in modo da sapere l’indirizzo dove si dovrà ritornare in uscita dalla subrou>ne •  I parametri possono anche essere variabili in uscita, che userà il programma chiamante Salvataggio dei registri
SP [ESI] [EDI] [EDX] Return address (PC) PAR1 PAR2 •  Se una subrou>ne deve usare del registri (diciamo ESI, EDI ed EDX) deve garan>re di non distruggere il loro contenuto, per poterlo ripris>nare in uscita PAR3 •  Li memorizza in cima allo stack Variabili locali e Frame
Pointer (FP)
•  In mol> linguaggi le subrou>nes possono avere variabili locali che non sono viste dal resto del programma e la cui memoria viene rilasciata all’uscita dalla subrou>ne •  Il luogo naturale di memorizzazione è nuovamente lo stack dove la memoria può essere assegnata all’ingresso in una subrou>ne e rilasciata in uscita •  Per mantenere chiaramente separate le variabili globali salvate nello stack e quelle locali si usa un ulteriore puntatore chiamato Frame Pointer Variabili locali e Frame
Pointer (FP)
SP saved [R1] saved [R0] localvar3 localvar2 localvar1 FP saved [FP] Return address Stack frame for called subrouKne param1 param2 param3 param4 Old TOS (top-­‐of-­‐stack) •  FP separa la parte di memoria dedicata al passaggio dei parametri dalla memoria locale •  I registri R1 ed R0 sono salva> perchè assumiamo che la subrou>ne li userà •  FP non varia durante l’esecuzione della subrou>ne Tipico Struttura di una funzione IA32
ESP saved register saved register localvar3 localvar2 localvar1 EBP saved [EBP] Return address param1 Stack frame for called subrouKne param2 param3 param4 Old TOS (top-­‐of-­‐stack) /* Prologo */ pushl %ebp /*salva ebp */ mov %esp, %ebp /*Memorizza inizio Frame afvazione */ sub $.., %esp /* alloca spazio per variabili locali*/ pushl %esi ... /* salva registri.. se occorre */ /* Corpo funzione */ ..... /* epilogo */ popl %esi... /* Ripris>na registri se salva> */ addl $.., %esp /* dealloca variabili locali */ movl %ebp, %esp /* Ripris>na ebp, esp */ popl %ebp /* Queste due istruz. equivalgono a leave*/ ret IA32 – gcc convenzioni di
chiamata
•  U>lizzando gcc, per rendere una funzione assembler invocabile dal C, occorre rispeJare le seguen> convenzioni:   I parametri vengono immessi sullo stack dal chiamante a par>re dall'ul>mo verso il primo.  as. es., all'interno della funzione troviamo in (%esp) l'indirizzo di ritorno, 4(%esp) il primo parametro, 8(%esp) il secondo (assumendo che il primo sia a 32 bit) ecc.   I registri esp, ebp, esi, edi, ebx devono essere preserva>  se si usano bisogna prima salvarli sullo stack e poi ripris>narli  i parametri di ritorno, se interi o puntatori, vengono res>tui> in eax Esempio su IA32
•  Si scriva una funzione Assembly che riceve come parametri
  un veJore di numeri interi a 8 bit con segno   il numero di elemen> del veJore, e res>tuisce la somma a 32-­‐bit di tuf gli elemen> posi>vi. Soluzione... Prologo
/* Prologo */ pushl %ebp /*salva ebp */ mov %esp, %ebp /*Memorizza inizio Frame acvazione */ pushl %esi /* salva registri, non ho variabili locali */ Soluzione... Corpo funzione
movl 8(%ebp), %esi movl 12(%ebp), %ecx xorl %eax, %eax /* azzero eax */ xorl %edx, %edx /* azzero eax */ jecxz .END /*Se ecx 0 finito */ .L0: movb (%esi), %dl testb %dl, %dl /*Come la and ma non salva il risultato e seQa solo i flag */ js .L1 /* se il numero è negaKvo non lo considero */ addl %edx, %eax .L1: incl %esi loop .L0 /* Decrementa ecx e salta se diverso da 0 */ Soluzione... Epilogo
.END: popl %esi /* RiprisKna registri se salvaK */ leave ret