Il contatore del programma su CPU Intel può essere letto direttamente (ovvero senza "trucchi") in modalità kernel o in qualche altra modalità?Contatore del programma di lettura direttamente
risposta
No, non è possibile accedere direttamente a EIP/IP, ma in codice dipendente dalla posizione è una costante di tempo di collegamento in modo da poter utilizzare un simbolo vicino (o distante) come immediato.
Per ottenere EIP o IP in codice indipendente dalla posizione:
call _here
_here: pop eax
; eax now holds the PC.
Ma questo sbilancia il predittore stack di chiamate/ritorno, in modo preferiscono chiamare una funzione che in realtà tornare, per evitare mispredicts filiali, il 15 o giù di lì future ret
istruzioni nelle funzioni genitore. (A meno che non hai intenzione di tornare, o almeno così di rado che non importa.)
get_retaddr:
mov eax, [esp]
ret ; keeps the return-address predictor stack balanced
In modalità x86-64, RIP possono essere letti direttamente tramite un RIP-relativa lea
.
default rel ; NASM directive: use RIP-relative by default
lea rax, [_here] ; RIP + 0
_here:
MASM: lea rax, [rip]
AT & sintassi T: lea 0(%rip), %rax
Se è necessario l'indirizzo di un'istruzione specifica, di solito qualcosa come questo fa il trucco:
thisone:
mov (e)ax,thisone
(Nota: su alcuni assemblatori ciò potrebbe fare la cosa sbagliata e leggere una parola da [thisone], ma di solito c'è qualche sintassi f o fare in modo che l'assemblatore faccia la cosa giusta.)
Se il codice viene caricato staticamente su un indirizzo specifico, l'assemblatore sa già (se gli hai detto l'indirizzo di partenza corretto) gli indirizzi assoluti di tutte le istruzioni. Il codice caricato dinamicamente, come parte di un'applicazione su qualsiasi sistema operativo moderno, otterrà il giusto indirizzo grazie al riposizionamento degli indirizzi eseguito dal linker dinamico (a condizione che l'assemblatore sia abbastanza intelligente da generare le tabelle di rilocazione, che di solito sono).
Grazie per le informazioni, buona idea in effetti.:) –
Ho provato questo su x86-64 con l'assembly gcc inline, ma ho avuto un errore nel backend: l'indirizzamento assoluto a 32 bit non è supportato in modalità a 64 bit usando llvm 6.1.0. È il problema di LLVM, o non è possibile in modalità 64-bit? – csl
@csl: o sei su OS X (dove non c'è soluzione alternativa all'utilizzo di 'lea rax, [thisone]'), o sei su Linux che crea un oggetto condiviso e quindi anche questo non può funzionare. ('mov'-immediate richiede un indirizzo costante di collegamento, quindi funziona solo in codice dipendente dalla posizione).Ma se stai realizzando un eseguibile Linux, [il tuo compilatore potrebbe impostare automaticamente un eseguibile indipendente dalla posizione e '-no-pie -fno-pie' rendere un eseguibile dipendente dalla posizione dove puoi usare l'indirizzamento assoluto] (https: //stackoverflow.com/questions/43367427/32-bit-absolute-addresses-no-longer-allowed-in-x86-64-linux). –
Non c'è alcuna istruzione per leggere direttamente il puntatore di istruzioni (EIP) su x86. È possibile ottenere l'indirizzo dell'istruzione corrente in fase di montaggio, con un po 'di assembly inline:
// GCC inline assembler; for MSVC, syntax is different
uint32_t eip;
__asm__ __volatile__("movl $., %0", : "=r"(eip));
La direttiva .
assembler viene sostituito con l'indirizzo dell'istruzione corrente dall'assembler. Si noti che se si avvolge lo snippet sopra riportato in una chiamata di funzione, si otterrà lo stesso indirizzo (all'interno di quella funzione) ogni volta. Se si desidera una funzione C più utilizzabile, è possibile invece utilizzare alcuni di montaggio non in linea:
// In a C header file:
uint32_t get_eip(void);
// In a separate assembly (.S) file:
.globl _get_eip
_get_eip:
mov 0(%esp), %eax
ret
Ciò significa che ogni volta che si desidera ottenere il puntatore all'istruzione, è un po 'meno efficiente in quanto è necessario una chiamata di funzione in più. Si noti che facendo in questo modo non soffiare lo stack di indirizzo di ritorno (RAS). Lo stack di indirizzo di ritorno è uno stack separato di indirizzi di ritorno utilizzati internamente dal processore per facilitare branch target prediction per istruzioni RET.
Ogniqualvolta si dispone di un'istruzione CALL, l'EIP corrente viene inserito nel RAS e ogni volta che si esegue un'istruzione RET, il RAS viene interrotto e il valore superiore viene utilizzato come predizione del target di diramazione per tale istruzione.Se si incasina il RAS (ad esempio non corrispondendo ad ogni CALL con un RET, come in Cody's solution), si otterrà un sacco di errate previsioni di rami inutili, rallentando il programma. Questo metodo non soffiare il RAS, poiché ha una coppia di istruzioni CALL e RET corrispondenti.
Grazie, ragazzi rock :) –
Mille grazie per le informazioni, non sapevo che c'erano due stack .. :) –
Il RAS è uno stack interno utilizzato dal processore; non è accessibile al codice in alcun modo. Viene utilizzato solo per la previsione del target di ramo. Senza di esso, il codice funzionerebbe ancora correttamente, solo più lentamente. –
Su x86-64 si può fare ad esempio:
lea rax,[rip] (48 8d 05 00 00 00 00)
Grazie! Qual è il significato dei numeri? –
questa è la codifica dell'istruzione - c'è un offset implicito a 32 bit che è 0, non sono sicuro se c'è una codifica più breve – matja
'lea rax, [rip]' non ha funzionato in NASM 2.10. Sembra che RIP possa essere usato solo indirettamente con 'rel' come in' lea rax, [rel _start] '? –
Si può anche leggere questo da/proc/stat. Controlla le manpage proc.
Puoi indicare dove? Non riuscivo a trovarlo facilmente. –
In/proc/stat puoi trovare il puntatore di istruzioni (EIP) –
Penso che tu intenda '/ proc/self/stat', sarebbe anche bello citare la manpage. –
Esiste un'architettura modo indipendente (ma gcc dipendente) di accedere al indirizzo che viene eseguito utilizzando etichette come valori:
http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
void foo()
{
void *current_address = $$current_address_label;
current_address_label:
....
}
Questo non è esattamente il montaggio :-) – hirschhornsalz
dovrebbe essere '&& current_address_label', non' $$ ' –
Non si tratta di un indirizzo relativo (non IP)? –
- 1. Differenza tra "contatore programma" e "indirizzo iniziale"
- 2. Perché abbiamo bisogno di un registro stackpointer quando abbiamo già il registro del contatore del programma?
- 3. Un programma può assegnare direttamente la memoria?
- 4. Chiunque programma ancora usando xlib direttamente
- 5. Android - Lettura di dati HTML5 localStorage direttamente da Java
- 6. Do shared_ptrs incontra errori di cache dovuti al contatore/incremento decrementale del contatore di riferimento?
- 7. AverageTimer32 valore del contatore diventa zero
- 8. Lettura dell'uscita binaria di un programma esterno in Common Lisp
- 9. aggiornamento del contatore distintivo a Swift
- 10. È possibile scrivere direttamente un programma con istruzioni bytecode Java?
- 11. Puntatore di istruzioni vs Contatore programmi?
- 12. lettura di un file XML in un programma C++
- 13. Nessuna funzione contiene il contatore di programma per il frame selezionato
- 14. C# errore: sezione di configurazione non riconosciuta userSettings - interrompe la lettura del programma user.config?
- 15. Perché Pascal vieta la modifica del contatore all'interno del blocco?
- 16. Posso ottenere il valore del contatore CSS del genitore?
- 17. Strumenti di lettura, comprensione e lettura del codice sorgente
- 18. La mancanza di avvertimenti sul contatore del ciclo
- 19. Contatore del tempo di compilazione nella classe template
- 20. La funzione di "piega" personalizzata ha bisogno del contatore
- 21. Apertura di un database di sola lettura direttamente nella cartella delle risorse
- 22. Dividere il risultato di 'contatore'
- 23. Contatore di colpi in magento
- 24. Consistenza contatore orologio multicore
- 25. Data di scadenza del cookie di lettura
- 26. Lettura del file DWARF in Mac OSX
- 27. Lettura del file dalla memoria BLOB di Azure
- 28. del programma java
- 29. Variabile contatore per classe
Ah, amo quel trucco. In ARM, ci sono problemi di pipeline durante la lettura del PC. Questo problema è presente anche nelle CPU Intel? – strager
No, non è presente su x86. (A proposito, il problema del pipel arm ARM è pazzesco) –
In x86, si ha il costo di un ramo, che è molto peggiore per la pipeline rispetto alla sola lettura del PC. PIC su ARM è molto più economico di x86, anche con le stranezze della pipeline. –