vuoi
o PayPal
tutte le volte che vuoi
%RBX %EBX %BX %BL Contatore
%RCX %ECX %CX %CL Dati
%RDX %EDX %DX %DL sorgente
%RSI %ESI %SI Destinazione
%RDI %EDI %DI
%R8 %R8D %R8W %R8B
%R9 %R9D %R9W %R9B
%R10 %R10D %R10W %R10B
%R11 %R11D %R11W %R11B
%R12 %R12D %R12W %R12B
%R13 %R13D %R13W %R13B
%R14 %R14D %R14W %R14B
%R15 %R15D %R15W %R15B
I registri in blu sono “callee-save”, gli altri caller-save
SYSTEM V ABI
Definisce le convenzioni per l’utilizzo dei registri
- %RAX
il valore di ritorno della funzione si salva in
- %RBP è il puntatore alla finestra di stack, all’inizio di ogni programma si inizializza allo
stesso valore di RSP in modo da usarlo come puntatore all’indirizzo iniziale dello stack
corrispondente, dove sono salvati in parametri in eccesso rispetto ai registri (PUSH)
- I primi 6 parametri della funzione devono essere salvati in RDI, RSI, RDX, RCX, R8, R9
nel caso di system call si usa R10 al posto di RCX
- callee-save
Registri => prima di poter utilizzare uno di questi registri bisogna salvarne
il contenuto sulla stack (PUSH) per poi ripristinarlo (POP) alla fine del programma.
Serve per evitare la perdita di dati nella funzione chiamante.
PUSHx S di x)
%rsp = %rsp - (tipo
(%rsp) = S
POPx D D = %rsp di x)
(%rsp) = %rsp + (tipo
OSS PUSH e POP possono essere usate in
generale per salvare sullo stack ogni tipo di
variabile in eccesso al numero di registri
ATTENZIONE le istruzioni modificano anche %rsp, cambiano tutti gli offset collegati 3
Istruzioni logico-aritmetiche
ADDx S, D D = D + S
SUBx S, D D = D - S
IMULx S, D D = D * S (operazione molto costosa)
XORx S, D D = D ^ S
ORx S, D D = D | S
ANDx S, D D = D & S
NOTx D D = ~D
NEGx D D = -D complemento a 2
INCx D D = D + 1
DECx D D = D - 1
LEAx S, D D = &S load effective address
ATTENZIONE non si possono avere 2 operandi a memoria contemporaneamente
Shift
Sposta tutti i bit di un registro destinazione del numero di posizioni date dalla sorgente
permettono moltiplicazioni e divisioni ottimizzate con potenze di 2
Shift logico aggiunge 0 in
shift logico aritmetico posizioni vuote
SX (left) SHLx SALx
S, D S, D Shift aritmetico conserva il
DX (right) segno
SHRx SALx
S, D S, D
Ottimizzazioni
1. Per settare a 0 un registro invece di MOV si può usare XOR
x = 0 movl $0, %eax xorl %eax, %eax
2. Invece di usare IMUL si possono usare addizioni consecutive, LEA o shift
x = x*2 imul $2, %eax addl %eax, %eax (loop per + di 2)
x = x*4 imul $4, %eax xorl %eax, %eax
leal (&ecx, %eax, 4)
sal $4, %eax (solo con potenze di 2)
x = x*16 imul $16, %eax log (16)
#4 = 2
3. Per equazioni è possibile usare la LEA invece di più istruzioni
x = z + 2y - 7 leal -7(%ecx, %edx, 2), %eax. (lea non effettua side effect su flags)
4. Moltiplocazione con shift-and-add (codice su appendice A)
A. Shift a destra del moltiplicando
B. IF (carry = 1) risultato += moltiplicatore
C. Shift a sinistra del moltiplicatore
D. Goto 1 (finché moltiplicando = 0) 4
If - else (salti)
Le istruzioni if - else vengono implementate in assemby tramite confronti e salti, prima si
effettua il test con CMP, dopodiché si usa Jcc per verificare condizione e nel caso saltare.
CMPx S, D calcola D - S
Jcc etichetta salto condizionato su etichetta, dipende da cc
JMP etichetta salto su etichetta, no condizioni
ATTENZIONE in questo modo si ha un sistema equivalente al goto, quindi nel caso di
normali condizioni di if bisogna ribaltare l'espressione
Condizioni
TEST CONDIZIONE CONDIZIONE C Assembly
(con segno) (senza segno) x ≤ y # x=%eax y=%ecx
If ( ) goto L
== e cmpl %ecx, %eax
!= ne jle L
< l b
≤ le be
> g a
≥ ge ae
Confronti tramite flags
Il calcolatore esegue i confronti tra le variabili tramite un operazione di sottrazione per poi
controllare lo stato dei flags e conoscere il risultato del confronto
OSS oltre alle normali condizioni di test si può usare direttamente lo stato dei flag per
effettuare operazioni salto, tramite:
Jnome_flag
JNnome_flag (la N permette di avere condizione inversa)
Cicli while-for
In entrambi i casi si imposta la condizione di ciclo con CMP e Jcc, se condizione fallisce
si eseguono operazioni fino a raggiungere JMP che salta nuovamente al test CMP
Nel caso di ciclo for la condizione si effettua su un contatore decrementato ad ogni loop 5
Le subroutine
Permettono di implementare le chiamate a funzione, la chiamata si effettua tramite
CALL RET.
l’istruzione il ritorno tramite la funzione Quindi ad ogni chiamata a funzione, la
CALL prima di saltare salva l'indirizzo
CALL nome_routine %rsp = %rsp - 8
(%rsp) = %rip di ritorno sulla cima dello stack, per
%rip = nome_routine poi recuperarlo alla fine tramite RET.
È quindi importante che alla fine del
RET %rip = %rsp programma tutte le alterazioni a
%rsp = %rsp + 8 %RSP vengano eliminate
Passaggio parametri funzioni
conventions”,
Definito dalle “calling si salvano sulla
cima dello stack i parametri (in eccesso ai registri) da
passare alla funzione prima di effettuare la chiamata.
1. Sottraggo a %RSP un numero di byte equivalente
a quelli necessari per salvare tutti i parametri
2. Tramite MOV e %RSP sposto i parametri sulla cima
dello stack (posso unire 1 e 2 usando push)
3. Eseguo istruzione CALL
4. Ripristino valore di %RSP
ATTENZIONE i parametri devono essere passati in
modo che il primo sia quello con l’indirizzo più basso
nella stack e gli altri crescano di conseguenza
C Assembly (mov) Assembly (push) NOTE
F( 10, 20) subq $16, %rsp pushq 20 bisogna comunque
movq $10, (%rsp) pushq 10 ripristinare valore
movq $10, 8(%rsp) call F originale di rsp in
call F addq $16, %rsp entrambi i casi
addq $16, %rsp
ATTENZIONE normalmente le variabili a 32 bit (o minori) dovrebbero essere promosse a
grandezza massima prima del CALL (in questo caso non necessario), %RSP non cambia
e le operazioni collegate ad esso devono essere effettuate comunque a 64 bit
Acquisizione parametri funzioni
L’acquisizione avviene in modo analogo andando a prelevare i parametri direttamente
dalla stack tramite l’offset di %RSP
C Assembly
Int F( long int x, long int y) f: movq 8(%rsp), %rax
addl 16(%rsp), %rax
ret
ATTENZIONE presenza indirizzo di ritorno e di eventuali altre modifiche al registro %RSP 6