597 Stimmen

GCC -fPIC-Option

Ich habe über GCC's Optionen für Code-Generierungskonventionen gelesen, aber ich habe nicht verstanden, was "Positionsunabhängigen Code generieren (PIC)" bedeutet. Bitte geben Sie mir ein Beispiel, um zu erklären, was das bedeutet.

47 Stimmen

Clang verwendet auch -fPIC.

4 Stimmen

0 Stimmen

Verwandt, aber kein Duplikat: stackoverflow.com/questions/23225566/…

731voto

Erik Punkte 85308

Position Independent Code bedeutet, dass der generierte Maschinencode nicht davon abhängig ist, an einer bestimmten Adresse platziert zu sein, um zu funktionieren.

Zum Beispiel würden Sprünge als relative und nicht als absolute generiert werden.

Pseudo-Assembly:

PIC: Dies würde funktionieren, egal ob der Code sich an Adresse 100 oder 1000 befindet.

100: VERGLEICHE REG1, REG2
101: SPRUNG_BEI_GLEICH AKTUELL+10
...
111: NOP

Non-PIC: Dies funktioniert nur, wenn der Code sich an Adresse 100 befindet.

100: VERGLEICHE REG1, REG2
101: SPRUNG_BEI_GLEICH 111
...
111: NOP

ÄNDERUNG: In Antwort auf den Kommentar.

Wenn Ihr Code mit -fPIC kompiliert wird, ist er für die Einbindung in eine Bibliothek geeignet - die Bibliothek muss in der Lage sein, von ihrer bevorzugten Speicheradresse an eine andere Adresse verschoben zu werden, möglicherweise befindet sich bereits eine andere Bibliothek an der Adresse, die Ihre Bibliothek bevorzugt.

55 Stimmen

Dieses Beispiel ist klar, aber als Benutzer, was wird der Unterschied sein, wenn ich eine gemeinsame Bibliothek (.so) Datei ohne die Option erstelle? Gibt es Fälle, in denen meine Bibliothek ohne -fPIC ungültig wird?

30 Stimmen

Ja, das Erstellen einer gemeinsam genutzten Bibliothek, die nicht PIC ist, könnte ein Fehler sein.

116 Stimmen

Um genauer zu sein, soll die gemeinsam genutzte Bibliothek zwischen Prozessen geteilt werden, aber es ist möglicherweise nicht immer möglich, die Bibliothek an derselben Adresse in beiden zu laden. Wenn der Code nicht positionsunabhängig wäre, würde jeder Prozess eine eigene Kopie benötigen.

87voto

Roee Gavirel Punkte 18058

Ich werde versuchen, das bereits Gesagte auf einfache Weise zu erklären.

Immer wenn eine gemeinsam genutzte Bibliothek geladen wird, ändert der Loader (der Code auf dem Betriebssystem, der jedes von Ihnen ausgeführte Programm lädt) einige Adressen im Code, je nachdem, wo das Objekt geladen wurde.

In dem obigen Beispiel wird die "111" im nicht-PIC-Code das erste Mal vom Loader geschrieben, als es geladen wurde.

Für nicht freigegebene Objekte möchten Sie dies möglicherweise so belassen, da der Compiler einige Optimierungen für diesen Code vornehmen kann.

Für freigegebene Objekte, wenn ein anderer Prozess zu diesem Code "verlinken" möchte, muss er ihn an die gleichen virtuellen Adressen lesen oder die "111" ergibt keinen Sinn. Aber dieser virtuelle Speicherplatz kann bereits im zweiten Prozess belegt sein.

2 Stimmen

Immer wenn eine gemeinsam genutzte Bibliothek geladen wird, ändert der Loader einige Adressen im Code, abhängig davon, wo das Objekt geladen wurde. Ich glaube, dass dies nicht korrekt ist, wenn mit -fpic kompiliert wird und der Grund, warum -fpic existiert, also aus Leistungsgründen oder weil Sie einen Loader haben, der nicht in der Lage ist, neu zu lokalisieren, oder weil Sie mehrere Kopien an verschiedenen Standorten benötigen oder aus vielen weiteren Gründen.

13 Stimmen

Warum nicht immer -fpic verwenden?

15 Stimmen

@Jay - weil für jeden Funktionsaufruf eine weitere Berechnung (die Funktionadresse) erforderlich ist. In Bezug auf die Leistung ist es daher besser, es nicht zu verwenden, wenn es nicht benötigt wird.

62voto

Jonathan Leffler Punkte 694013

Code, das in gemeinsame Bibliotheken eingebettet ist, sollte normalerweise positionsunabhängigen Code sein, so dass die gemeinsame Bibliothek problemlos an (mehr oder weniger) jeder Adresse im Speicher geladen werden kann. Die -fPIC-Option stellt sicher, dass GCC einen solchen Code erzeugt.

1 Stimmen

Warum würde eine gemeinsam genutzte Bibliothek ohne das -fPIC-Flag nicht an irgendeiner Speicheradresse geladen werden? Ist sie nicht mit dem Programm verknüpft? Wenn das Programm ausgeführt wird, lädt das Betriebssystem es in den Speicher hoch. Fehlt mir etwas?

1 Stimmen

Wird das -fPIC-Flag verwendet, um sicherzustellen, dass diese Bibliothek an jede virtuelle Adresse im Prozess geladen werden kann, der sie verknüpft? Entschuldigung für doppelte Kommentare. 5 Minuten vergangen, konnte den vorherigen nicht bearbeiten.

2 Stimmen

Unterscheiden Sie zwischen dem Erstellen der gemeinsam genutzten Bibliothek (Erstellen von libwotnot.so) und dem Verknüpfen damit (-lwotnot). Beim Verknüpfen müssen Sie sich nicht um -fPIC kümmern. Früher mussten Sie sicherstellen, dass beim Erstellen der gemeinsam genutzten Bibliothek -fPIC für alle Objektdateien verwendet wurde, die in die gemeinsam genutzte Bibliothek eingebaut werden sollten. Die Regeln können sich geändert haben, da Compiler heutzutage standardmäßig mit PIC-Code erstellen. Was vor 20 Jahren wichtig war und vor 7 Jahren wichtig sein konnte, ist meiner Meinung nach heutzutage weniger wichtig. Adressen außerhalb des Betriebssystemkernels sind immer virtuelle Adressen.

29voto

Ritesh Punkte 1737

Weiter hinzufügen...

Jeder Prozess hat denselben virtuellen Adressraum (Wenn die Randomisierung der virtuellen Adresse durch Verwendung eines Flags im Linux-Betriebssystem gestoppt wird) (Weitere Einzelheiten Deaktivieren und erneut aktivieren der Adressraumlayout-Randomisierung nur für mich)

Wenn es sich also um eine ausführbare Datei ohne gemeinsame Verknüpfung handelt (hypothetisches Szenario), können wir immer derselben asm-Anweisung dieselbe virtuelle Adresse ohne Schaden zu verursachen zuweisen.

Aber wenn wir ein gemeinsam genutztes Objekt mit der ausführbaren Datei verknüpfen möchten, sind wir uns nicht sicher über die Startadresse, die dem gemeinsam genutzten Objekt zugewiesen wird, da dies von der Reihenfolge abhängt, in der die gemeinsam genutzten Objekte verknüpft wurden. Dies bedeutet, dass die asm-Anweisung innerhalb der .so-Datei immer eine andere virtuelle Adresse haben wird, abhängig vom Prozess, mit dem sie verknüpft ist.

Ein Prozess kann also der .so-Datei im eigenen virtuellen Speicher eine Startadresse von 0x45678910 zuweisen, während ein anderer Prozess zur gleichen Zeit eine Startadresse von 0x12131415 zuweisen kann und wenn sie nicht die relative Adressierung verwenden, funktioniert die .so-Datei überhaupt nicht.

Deshalb müssen sie immer den relativen Adressierungsmodus und daher die fpic-Option verwenden.

1 Stimmen

Danke für die Erklärung der virtuellen Adresse.

2 Stimmen

Kann jemand erklären, wie dies kein Problem bei einer statischen Bibliothek ist, warum Sie bei einer statischen Bibliothek kein -fPIC verwenden müssen? Ich verstehe, dass die Verknüpfung zur Kompilierzeit erfolgt (oder tatsächlich sofort danach), aber wenn Sie 2 statische Bibliotheken mit positionsabhängigem Code haben, wie werden sie verknüpft?

3 Stimmen

@MichaelP Objektdatei hat eine Tabelle von positionsabhängigen Labels, und wenn eine bestimmte Objektdatei verknüpft ist, werden alle Labels entsprechend aktualisiert. Dies kann nicht für gemeinsam genutzte Bibliotheken durchgeführt werden.

18voto

user1016759 Punkte 139

Eine kleine Ergänzung zu den bereits veröffentlichten Antworten: Nicht als positionsunabhängig kompilierte Objektdateien sind verschiebbar; sie enthalten Einträge in der Relokationstabelle.

Diese Einträge ermöglichen es dem Loader (dieser Codeabschnitt, der ein Programm in den Speicher lädt), die absoluten Adressen umzuschreiben, um sie an die tatsächliche Ladeadresse im virtuellen Adressraum anzupassen.

Ein Betriebssystem wird versuchen, eine einzelne Kopie einer "Shared Object Library", die im Speicher geladen ist, mit allen Programmen gemeinsam zu nutzen, die mit derselben Shared Object Library verknüpft sind.

Da der Code-Adressraum (im Gegensatz zu Abschnitten des Datenspeichers) nicht zusammenhängend sein muss und weil die meisten Programme, die mit einer bestimmten Bibliothek verknüpft sind, einen ziemlich festen Bibliotheksabhängigkeitsbaum haben, gelingt dies meistens. In den seltenen Fällen, in denen es Abweichungen gibt, kann es erforderlich sein, zwei oder mehr Kopien einer Shared Object Library im Speicher zu haben.

Offensichtlich wird jeder Versuch, die Ladeadresse einer Bibliothek zwischen Programmen und/oder Programminstanzen zu randomisieren (um die Möglichkeit der Erstellung eines ausnutzbaren Musters zu reduzieren), solche Fälle häufiger auftreten lassen, nicht selten, also sollte man, wo ein System diese Funktion ermöglicht hat, jeden Versuch unternehmen, alle Shared Object Libraries so zu kompilieren, dass sie positionsunabhängig sind.

Da auch Aufrufe in diese Bibliotheken aus dem Hauptprogramm heraus verschiebbar gemacht werden, ist es viel unwahrscheinlicher, dass eine Shared Library kopiert werden muss.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X