2014-11-16 4 views
10

Poiché utilizzo objdump -D per disassemblare un binario, il codice tipico di jmpq è come e9 7f fe ff ff, che viene utilizzato per rappresentare un offset negativo. Tuttavia, l'indirizzo x86-64 è 64 (48) -bit (a mia conoscenza), quindi come può questo indirizzo a 32 bit 7f fe ff ff rappresentare l'offset negativo dell'indirizzo assoluto a 64 bit?Perché jmpq di x86-64 richiede solo l'indirizzo di lunghezza a 32 bit?

Inoltre, esistono altre istruzioni come jmp e jmpq, ma con spostamento dell'indirizzo a 64 bit? Come posso trovare le istruzioni nel manuale di Intel o AMD (ho cercato jmpq ma non ho trovato nulla)?


Come ho cercato, sembra essere chiamato indirizzamento relativo a RIP. E sembra che non tutte le istruzioni lo facciano. C'è un indirizzamento relativo a 64 bit? Se si tratta di un salto indiretto, l'indirizzo assoluto a 64 bit si troverà in un registro o in una memoria, giusto?

+0

L'istruzione di salto ha una versione offset a 32 bit. Se l'offset si adatta a 32 bit, è possibile utilizzare la versione offset a 32 bit e salvare alcuni byte (su un indirizzo assoluto a 64 bit o altro). –

+0

Grazie per il commento. Qual è l'istruzione della versione offset a 64 bit? – WindChaser

+1

Non credo ci sia una versione offset a 64 bit. –

risposta

7

Come altri hanno notato, l'istruzione "jmp relativo" per x86-64 è limitata a uno spostamento firmato a 32 bit, utilizzato come offset relativo rispetto al contatore del programma.

OP chiesto perché non è presente un salto relativo con offset a 64 bit. Non posso parlare per i progettisti di Intel, ma sembra abbastanza chiaro che questa istruzione semplicemente non sarebbe molto utile, specialmente con la disponibilità della jmp relativa a 32-bit. L'unica volta che sarebbe necessario è quando il tuo programma aveva una dimensione di 2+ gigabyte, in modo che la jmp relativa a 32 bit non potesse raggiungerla da qualsiasi punto al suo interno. Hai visto qualche file oggetto 2Gb recentemente? Quindi l'apparente utilità per tali istruzioni sembra davvero piccola.

Principalmente quando i programmi diventano molto grandi, iniziano a essere suddivisi in elementi più gestibili che possono evolvere a velocità diverse. (DLL sono un esempio di questo). Interfacciare tra tali elementi è fatto con mezzi più arcani (vettori di salto, ecc.) Per garantire che le interfacce rimangano costanti di fronte all'evoluzione. Un parente jmp estremamente lungo può essere utilizzato per raggiungere da un'applicazione a un punto di ingresso in un altro modulo, ma il costo effettivo del caricamento di un indirizzo assoluto in un registro e di una chiamata indiretta al registro è abbastanza piccolo in pratica che non è Vale la pena ottimizzare. Il design moderno della CPU si basa sull'ottimizzazione di dove si mettono i transistor per massimizzare le prestazioni.

Giusto per essere completo, l'x86 (molte versioni) ha istruzioni relative jmp molto brevi (offset con segno a 8 bit). In pratica, anche le istruzioni relative jmp a 32 bit sono raramente necessarie, specialmente se si dispone di un buon generatore di codice che può riorganizzare blocchi di codice. Intel probabilmente avrebbe potuto escluderli per lo stesso motivo; Sospetto che la loro utilità sia abbastanza alta da giustificare i transistor.

La domanda di "grandi operandi letterali" si presenta in modi divertenti in molte architetture. Se si esamina la distribuzione dei valori letterali nel codice, si scoprirà che i valori piccoli (0,1, codici carattere ASCII) coprono una percentuale piuttosto buona; quasi tutto il resto sono indirizzi di memoria. Quindi non hai bisogno di "grandi valori letterali" nei programmi ma devi gestire gli indirizzi di memoria in qualche modo. Il chip Sparc ha notoriamente "carica letteralmente il valore basso nel registro" (che significa "piccole costanti") e meno spesso usato "carica letteralmente il valore alto" (per riempire i bit superiori in un registro) usato come seconda istruzione per creare costanti grandi, e usato meno spesso. Ciò mantiene il codice piccolo, tranne quando hai bisogno di una grande costante; codice piccolo significa più alto tasso di recupero delle istruzioni efficace e che contribuisce alle prestazioni.

+0

MIPS ha 'lui' per caricare anche una parte alta a 16 bit. La parte inferiore può essere caricata con 'ori' o' addiu'. ARM può caricare immediati a 8 bit con valori di rotazione uniformi, ma le versioni più recenti possono anche caricare separatamente parti a 16 bit ad alta e bassa –

5

Il codice operativo E9 in modalità a 64 bit di rimessa segno a 32 bit di segno spostamento esteso a 64 bit:

E9 cd -> JMP rel32 -> Vai vicino, parente, RIP = RIP + 32 bit segno spostamento esteso a 64 bit

Il codice operativo FF può essere usato per saltare ad un indirizzo a 64 bit:

FF/4 -> JMP R/M64 -> Vai vicino, assoluta indiretta, RIP = 64 bit di fset dal registro o la memoria

Citazioni tratte dal Intel instruction set manual entry for JMP.

+2

Che cosa significa "/ 4"?E se il primo bit è 1 (il primo byte varia da "8" a "f", l'offset verrà automaticamente esteso, come "ff ff ff ff ff 12 34 56")? – WindChaser

+0

È bene che tu ti riferisca al manuale Intel ma potresti spiegare per quelli che non hanno familiarità con la terminologia nel manuale che cosa significano 'cd' e'/4'. –

+0

Il/4 significa "estensione opcode". Vedi il mio post qui: https://stackoverflow.com/questions/26824941/opcode-ff-4-which-value-is-give-to-eip/26830328#26830328 – zx485

1

Quanto segue si applica alla modalità 64 bit.

JMP può essere eseguito direttamente o indirettamente.

I salti diretti sono relativi al puntatore di istruzioni RIP. Esistono due tipi di salti diretti: brevi e vicini.

  • salti brevi usa Opcode EB seguito da uno spostamento con segno a 8 bit e sono quindi RIP –128 to +127 byte.
  • I salti vicini utilizzano l'Opcode E9 e sono seguiti da un dislocamento firmato a 32 bit e pertanto sono RIP -2147483648 to +2147483647.

L'assemblatore utilizzerà salti brevi quando è possibile poiché hanno solo bisogno di due byte. Ma in NASM puoi forzare un salto vicino usando la parola chiave near ad es.

test: 
    jmp test   ; eb fb 
    jmp near test ; e9 f6 ff ff ff 

modalità di indirizzamento a 64 bit sono: RIP-relativa, 32 bit assoluta, 64 bit assoluta e relativa ad un puntatore base. L'istruzione JMP può utilizzare tutti questi eccetto i 64 bit assoluti. I salti indiretti utilizzano l'Opcode FF. Alcuni esempi che utilizzano la sintassi NASM:

jmp [a]    ;ff 24 25 00 00 00 00 - 32-bit absolute 
jmp [rel a]   ;ff 25 e7 ff ff ff - RIP + 32-bit displacement 
jmp [rdi]    ;ff 27    - base pointer 
jmp [rdi +4*rsi + a] ;ff a4 b7 00 00 00 00 - base pointer +4*index + displacement 

On OSX, however, 32-bit absolute addressing is not possible because the image base is greater than 2^32.

L'unica istruzione che può utilizzare l'indirizzamento assoluto a 64 bit è mov e quindi l'origine o la destinazione deve essere AL, AX, EAX or RAX. Es. In NASM

mov rax, [qword a] 
+0

'jmp [rdi]' è il salto a un "indirizzo assoluto" a 64 bit memorizzato in un byte di 8 byte indirizzo di memoria, che è il valore del registro 'rdi', giusto? – WindChaser

+0

@WindChaser, giusto. –

+0

@WindChaser risulta che si può anche fare 'jump rdi'. –

Problemi correlati