Perché tutto il codice compilato non è indipendente dalla posizione?


87

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?


2
Ma wowest non è del tutto corretto. Molte chiamate di funzioni e salti utilizzano salti relativi, quindi non hanno nemmeno bisogno di una tabella di salto dopo essere stati spostati.
Sconosciuto

guardando il codice assembly generato sembra che l'indirizzo della funzione sia caricato mentre in codice non fpic sembra che sia semplicemente un salto. Sto fraintendendo la tua dichiarazione?
ojblass

@ojblass quello che voglio dire è che alcuni salti sono come "salta 50 istruzioni avanti rispetto a qui" o "salta 5 istruzioni indietro" invece di "salta a 0x400000". Quindi, per dire che devi caricare un indirizzo ogni volta con -fPIC non è del tutto vero.
Sconosciuto

L' articolo di Wikipedia fornisce una buona descrizione. Fondamentalmente, su alcune architetture non esiste un modo diretto per saltare a un indirizzo relativo. Quindi, PIC è più costoso da usare su quegli archi. Vedi la risposta di @ EvanTeran per maggiori informazioni.
Alexei Sholik

Risposte:


68

Aggiunge un riferimento indiretto. Con il codice indipendente dalla posizione devi caricare l'indirizzo della tua funzione e poi saltare ad esso. Normalmente l'indirizzo della funzione è già presente nel flusso di istruzioni.


33

Questo articolo spiega come funziona PIC e lo confronta con l'alternativa: trasferimento del tempo di caricamento . Penso sia rilevante per la tua domanda.


16
@ Nick: non sono d'accordo. Se aiuta il richiedente, è una risposta. Indicare uno o due articoli pertinenti può fornire una grande quantità di informazioni.
Eli Bendersky

5
Non ci sono conclusioni in questo post, solo un collegamento a un articolo. Nemmeno un indizio che PIC non viene utilizzato di default a causa di problemi di prestazioni.
Nick

10
Sebbene questo collegamento possa rispondere alla domanda, è meglio includere le parti essenziali della risposta qui e fornire il collegamento come riferimento. Le risposte di solo collegamento possono diventare non valide se la pagina collegata cambia.
Rob

4
@ Rob: la cosa produttiva sarebbe suggerire una modifica e non usare commenti per lamentarsi. Questa risposta ha 4 anni. Allora SO aveva regole meno rigorose su come dovrebbe apparire una risposta
Eli Bendersky

6
Questo post è apparso in "revisione" chiedendomi di farlo e l'ho fatto. Qualcun altro l'ha segnalato. Il "commento lamentoso" è prodotto automaticamente da SO, non da me.
Rob il

27

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.

http://en.wikipedia.org/wiki/Position_independent_code


23

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:

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.


1
IIRC MIPS non ha anche l'indirizzamento relativo al PC, ad eccezione dei salti relativi
phuclv

1
Questa è una tecnica comune utilizzata nello shellcode per ottenere l'indirizzo da cui viene eseguito. L'ho usato in alcune soluzioni CTF.
sherrellbc

2

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.


1

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.


4
Ma anche con un codice PIC VM-MMU è necessario per garantire che la stessa libreria .so venga caricata una sola volta in memoria quando viene utilizzata da eseguibili diversi.
mmmmmmmm

1

position-independent code ha un sovraccarico delle prestazioni sulla maggior parte delle architetture, perché richiede un registro aggiuntivo.

Quindi, questo è a scopo di performance.


0

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ò.


-5

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".


Questa è solo un'affermazione di fatti: 10 anni fa il PIC era opzionale, ma oggi è predefinito e obbligatorio. Dubito che il codice non PIE sarà supportato in ulteriori versioni del sistema operativo. Proprio come il supporto della modalità reale è stato abbandonato dopo Windows 9x. Quindi la domanda da usare o non usare PIC diventa più un argomento teorico dell'informatica, a meno che in qualche modo non sblocchi il tuo sistema operativo e riattivi il supporto per esso. La cosa più importante che le persone devono sapere su PIC è che è abbastanza lento da consentire ai compilatori fino ad ora di supportare la compilazione statica, e c'erano versioni statiche della maggior parte delle DLL.
SmugLispWeenie

2
Le tue prime due frasi sono solo una dichiarazione di fatti. Il resto è opinione, al limite della cospirazione.
Mitch Lindgren

Bene, parla con le persone, chiedi la loro opinione al riguardo. Personalmente ho scoperto che PIC vs non-PIC è diventata anche una questione di ideologia. PIC è l'equivalente di programmazione del comunismo, dove il codice è prodotto in serie e tutti ricevono la stessa copia. Non-PIC è un equivalente di programmazione del capitalismo, dove esistono molte versioni concorrenti dello stesso codice. Quindi le persone con una mentalità più di sinistra inconsciamente supportano PIC per dimostrare il punto che la loro ideologia preferita potrebbe funzionare almeno nell'informatica. Queste stesse persone ti sconsigliano di usare libpng modificate personalmente.
SmugLispWeenie

3
Possiamo non avere invettive politiche su un sito web di programmazione, grazie
Ryan McCampbell
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.