Quando si compilano le librerie condivise in gcc, l'opzione -fPIC compila il codice come indipendente dalla posizione. C'è qualche motivo (prestazioni o altro) per cui non compileresti tutto il codice indipendentemente dalla posizione?
Quando si compilano le librerie condivise in gcc, l'opzione -fPIC compila il codice come indipendente dalla posizione. C'è qualche motivo (prestazioni o altro) per cui non compileresti tutto il codice indipendentemente dalla posizione?
Risposte:
Questo articolo spiega come funziona PIC e lo confronta con l'alternativa: trasferimento del tempo di caricamento . Penso sia rilevante per la tua domanda.
Sì, ci sono motivi di prestazioni. Alcuni accessi sono effettivamente sotto un altro livello di riferimento indiretto per ottenere la posizione assoluta in memoria.
C'è anche la GOT (Global offset table) che memorizza gli offset delle variabili globali. Per me, questo sembra solo una tabella di correzione IAT, che è classificata come dipendente dalla posizione da wikipedia e poche altre fonti.
Oltre alla risposta accettata. Una cosa che danneggia molto le prestazioni del codice PIC è la mancanza di "indirizzamento relativo IP" su x86. Con l '"indirizzamento relativo IP" è possibile richiedere dati che sono X byte dal puntatore dell'istruzione corrente. Ciò renderebbe il codice PIC molto più semplice.
I salti e le chiamate, di solito, sono relativi all'EIP, quindi non rappresentano un problema. Tuttavia, l'accesso ai dati richiederà un piccolo trucco in più. A volte, un registro verrà temporaneamente riservato come "puntatore di base" ai dati richiesti dal codice. Ad esempio, una tecnica comune è abusare del modo in cui le chiamate funzionano su x86:
call label_1
.dd 0xdeadbeef
.dd 0xfeedf00d
.dd 0x11223344
label_1:
pop ebp ; now ebp holds the address of the first dataword
; this works because the call pushes the **next**
; instructions address
; real code follows
mov eax, [ebp + 4] ; for example i'm accessing the '0xfeedf00d' in a PIC way
Questa e altre tecniche aggiungono un livello di riferimento indiretto agli accessi ai dati. Ad esempio, la GOT (Global offset table) usata dai compilatori gcc.
x86-64 ha aggiunto una modalità "RIP relativo" che rende le cose molto più semplici.
Perché l'implementazione del codice completamente indipendente dalla posizione aggiunge un vincolo al generatore di codice che può impedire l'uso di operazioni più veloci o aggiungere passaggi aggiuntivi per preservare quel vincolo.
Questo potrebbe essere un compromesso accettabile per ottenere il multiprocessing senza un sistema di memoria virtuale, in cui ritieni che i processi non invadano la memoria reciproca e potrebbe essere necessario caricare una particolare applicazione a qualsiasi indirizzo di base.
In molti sistemi moderni i compromessi sulle prestazioni sono diversi e un caricatore che si trasferisce è spesso meno costoso (costa qualsiasi codice di tempo viene caricato per la prima volta) rispetto al meglio che un ottimizzatore può fare se ha libero sfogo. Inoltre, la disponibilità di spazi di indirizzi virtuali nasconde in primo luogo la maggior parte delle motivazioni per l'indipendenza dalla posizione.
Inoltre, l'hardware della memoria virtuale nella maggior parte dei processori moderni (utilizzato dalla maggior parte dei sistemi operativi moderni) significa che un sacco di codice (tutte le app dello spazio utente, salvo l'uso bizzarro di mmap o simili) non deve essere indipendente dalla posizione. Ogni programma ottiene il proprio spazio di indirizzi che pensa inizia da zero.
position-independent code ha un sovraccarico delle prestazioni sulla maggior parte delle architetture, perché richiede un registro aggiuntivo.
Quindi, questo è a scopo di performance.
Al giorno d'oggi il sistema operativo e il compilatore di default rendono tutto il codice come codice indipendente dalla posizione. Prova a compilare senza il flag -fPIC, il codice verrà compilato correttamente ma riceverai solo un avviso. Le finestre del sistema operativo utilizzano una tecnica chiamata mappatura della memoria per ottenere ciò.
La domanda risale al 2009. Sono passati dieci anni e ora tutto il codice è effettivamente indipendente dalla posizione. Questo è ora applicato dai sistemi operativi e dai compilatori. Non c'è modo di rinunciare. Tutto il codice viene compilato forzatamente con PIE e il flag -no-pic / -no-pie viene ignorato, come parte di questa scusa ASLR. Il motivo è rallentare le app precedentemente veloci e vendere hardware più recente, con il pretesto di una maggiore sicurezza. Questo è completamente irrazionale, perché ora le grandi dimensioni di memoria ci consentono di sbarazzarci dell'inferno del collegamento dinamico, compilando staticamente tutte le app.
Lo stesso è accaduto prima, quando le persone accettavano silenziosamente la modalità reale e altre libertà che venivano portate via. E mi dispiace, MMU subisce un forte rallentamento, a causa dei cambi di contesto e della latenza di traduzione degli indirizzi. Non troverai MMU in sistemi critici per le prestazioni, come quelli usati dagli scienziati per campionare esperimenti di fisica.
Non ti lamenti, perché non sai nemmeno che il tuo codice è ostacolato da tutte queste rotelle. Cosa posso dire? Goditi subito un software 2 volte più lento con il loro PIC! Inoltre, con l'avvento di LLVM, presto verrà applicato JIT (codice gestito), senza accesso all'assembly inline x86, che rallenterà ulteriormente qualsiasi codice C / C ++. "Chi sacrifica la libertà per la sicurezza non merita nessuno dei due".