2009-02-13 24 views
7

A scuola abbiamo utilizzato un programma di bootstrap per eseguire programmi stand-alone senza un sistema operativo. Ho studiato questo programma e quando la modalità protetta è abilitata c'è un salto in avanti eseguito assemblando direttamente l'opcode e gli operandi come dati all'interno del programma. Questo è stato per l'assemblatore GNU:Qualcuno può spiegare questo opcode JMP x86 assemblato direttamente?


     /* this code immediately follows the setting of the PE flag in CR0 */

.byte 0x66, 0xEA 
.long TARGET_ADDRESS 
.word 0x0010   /* descriptor #2, GDT, RPL=0 */ 

Prima di tutto, perché uno vuole fare questo (al posto del mnemonico istruzioni)?

Ho dato un'occhiata ai manuali Intel, ma sono ancora un po 'confuso dal codice. Specificamente nel Volume 2A, pagina 3-549, c'è una tabella di codici operativi. La voce in questione:

 
EA *cp* JMP ptr16:32 Inv. Valid Jump far, absolute, address given in 
operand 

Il codice operativo attuale è ovvio, ma il primo byte, 0x66, mi ha confuso. Riferendosi alla tabella del manuale Intel, il cp apparentemente significa che seguirà un operando da 6 byte. E ovviamente 6 byte seguono nelle prossime due righe. 0x66 codifica un prefisso di override della dimensione dell'operando. Cosa c'entra questo con il cp nella tabella? Mi aspettavo che ci fosse qualche valore esadecimale per il cp, ma invece c'è questo prefisso override. Qualcuno può chiarire questo per me?

Ecco una discarica da od:

 
c022 **ea66 0000 0001 0010** ba52 03f2 c030 

TARGET_ADDRESS è stata definita come 0x00010000.

Sono anche un po 'confuso dal significato degli ultimi due byte. Tuttavia, questa sembra essere un'altra domanda. Sta diventando piuttosto tardi, e ho guardato il codice e i manuali Intel per ore, quindi spero di aver capito il punto.

Grazie per la ricerca!

+0

Le persone utilizzano opcodes (invece di istruzioni) per 2 motivi.La prima ragione è quando l'assemblatore è "meno che adeguato" e non fornisce supporto per le istruzioni di cui hanno bisogno (questo è/era comune quando vengono aggiunte nuove istruzioni e gli assemblatori più anziani non le supportano ancora). La seconda ragione è quando l'assemblatore supporta le istruzioni di cui hanno bisogno ma il programmatore non sa come convincere l'assemblatore a generarlo. Fondamentalmente, si tratta di cattivi strumenti (compresi vecchi strumenti, sintassi confusa e/o cattiva documentazione) o programmatori cattivi. – Brendan

+0

Nota: il mio commento sopra è "in generale" e si applica a tutti gli assemblatori. Non uso GAS e non ho idea se supporti l'istruzione "salto lontano a 32 bit nel codice a 16 bit" o meno (o quanto sia buona/cattiva la documentazione). – Brendan

risposta

12

Il 0x66 indica che JMP (0xEA) si riferisce a sei byte. L'impostazione predefinita si riferisce a 64 K (16 bit) in modalità reale oa 32 bit in modalità protetta (se ricordo bene). Avendolo aumentato, include anche il descrittore di segmento, l'indice del segmento nel GDT o nel LDT, il che significa che questo codice sta facendo quello che tradizionalmente si chiama "salto in lungo": un salto che attraversa oltre i segmenti nel architettura x86. Il segmento, in questo caso, punta alla seconda voce sul GDT. Se guardi prima in quel programma, probabilmente vedrai come il GDT è definito in termini di inizio e lunghezza del segmento (guarda il manuale di Intel per studiare le tabelle GDT e LDT, voce a 32 bit che descrive ciascun segmento).

+0

Ah, questo ha senso ora. In precedenza, quando il GDT è definito, la prima voce è nullo (come dice il manuale), ma il secondo è il segmento di codice. Dopo aver riletto alcune parti del manuale, sto vedendo come funziona. Grazie per il chiarimento. –

+0

Ancora una volta, sono ancora curioso di sapere perché l'autore abbia scelto di farlo invece di usare i mnemonici. –

+0

È il prefisso della dimensione dell'operando, ma lo cambia da ['jmp ptr16: 16' a' jmp ptr16: 32'] (http://felixcloutier.com/x86/JMP.html). Questa risposta afferma che la versione senza prefisso sarebbe 'jmp rel16' o' jmp rel32', ma questo è un diverso codice operativo, 'E9' non' EA'. 'EA' è sempre un far-jmp con offset e segmento immediati. –

2

Mi sono imbattuto in questo un po '. Alcuni assemblatori salteranno su un'ETICHETTA. In questo caso la persona vuole fare un salto in assoluto verso uno specifico offset hard coded. jmp TARGET_ADDRESS non funziona Immagino, quindi lo inseriscono come byte per ovviare a questo problema.

0

0x66 specifica l'override della dimensione dell'operando della dimensione del segmento di codice corrente. Supponendo che la dimensione corrente del codice sia di 16 bit, il nuovo puntatore di istruzioni sarà a 32 bit, non a 16 bit. Se la dimensione del segmento di codice corrente è a 32 bit, il 0x66 renderà il puntatore dell'istruzione di destinazione come 16 bit. L'attributo della dimensione del codice corrente dipende dal selettore CS in uso e dai relativi attributi caricati dalla tabella GDT/LDT. Nella modalità reale la dimensione del segmento di codice è solitamente di 16 bit, tranne casi speciali di modalità "irreale".