Frage

Diese Frage bezieht sich auf Dieses hier sowie seine Antwort.

Ich habe gerade etwas Hässlichkeit in einem Build entdeckt, an dem ich arbeite. Die Situation sieht dem folgenden (geschrieben im GMAKE -Format) aus; Hinweis, dies gilt speziell für ein 32-Bit-Speichermodell für SPARC- und X86-Hardware:

OBJ_SET1  := some objects
OBJ_SET2  := some objects

# note: OBJ_SET2 doesn't get this flag
${OBJ_SET1} : CCFLAGS += -PIC

${OBJ_SET1} ${OBJ_SET2} : %.o : %.cc
  ${CCC} ${CCFLAGS} -m32 -o ${@} -c ${<}

obj1.o       : ${OBJ_SET1}
obj2.o       : ${OBJ_SET2}
sharedlib.so : obj1.o obj2.o
obj1.o obj2.o sharedlib.so :
  ${LINK} ${LDFLAGS} -m32 -PIC -o ${@} ${^}

Es kann eindeutig funktionieren, Objekte zu mischen, die mit und ohne Bild in einem gemeinsamen Objekt zusammengestellt wurden (dies wird seit Jahren verwendet). Ich weiß nicht genug über das Bild, um zu wissen, ob es eine gute Idee/klug ist, und ich vermute in diesem Fall, es wird nicht benötigt, sondern es geschieht, weil es jemandem nicht genug war, um den richtigen Weg zu finden, um es beim Anlegen zu tun auf neue Sachen zum Build.

Meine Frage ist:

  1. Ist das sicher
  2. Ist es eine gute Idee
  3. Welche potenziellen Probleme können infolgedessen auftreten
  4. Wenn ich alles auf das Bild wende, gibt es nicht offensichtliche Gotchas, auf die ich achten möchte.
War es hilfreich?

Lösung

Ich habe vergessen, dass ich diese Frage sogar geschrieben habe.

Einige Erklärungen sind zuerst in Ordnung:

  • Nicht-Pic-Code kann vom Betriebssystem in [den meisten?] Modernem OSS in eine Position im Speicher geladen werden. Nachdem alles geladen wurde, durchläuft es eine Phase, in der das Textsegment festgelegt wird (wo das ausführbare Zeug endet), sodass es globale Variablen korrekt behandelt. Um dies zu schaffen, muss das Textsegment beschreibbar sein.
  • PIC -ausführbare Daten können einmal vom Betriebssystem geladen und über mehrere Benutzer/Prozesse teilnehmen. Damit das Betriebssystem dies tut, muss das Textsegment jedoch schreibgeschützt sein-was keine Einrichtungen bedeutet. Der Code wird für eine globale Offset-Tabelle (GOT) zusammengestellt, damit er sich im Verhältnis zu Globalen befassen kann, um die Notwendigkeit von Fixierungen zu lindern.
  • Wenn ein gemeinsames Objekt ohne Bild gebaut wird, obwohl es stark ermutigt wird, scheint es nicht, dass es streng notwendig ist. Wenn das Betriebssystem das Textsegment festlegen muss, ist es gezwungen, es in Speicher zu laden, das mit dem Leseschreiben gekennzeichnet ist ... was das Teilen über Prozesse/Benutzer hinweg verhindert.
  • Wenn eine ausführbare Binärdatei gebaut wird / mit / Bild, weiß ich nicht, was unter der Motorhaube schief geht, aber ich habe gesehen, wie einige Werkzeuge instabil werden (mysteriöse Abstürze & dergleichen).

Die Antworten:

  • Das Mischen von PIC/Nicht-Pic oder die Verwendung von PIC in ausführbaren Funktionen kann die Instabilitäten schwer vorhersagen und aufspüren. Ich habe keine technische Erklärung dafür, warum.
    • ... um Segfaults, Busfehler, Stapelversorgung und wahrscheinlich noch mehr einzubeziehen.
  • Nicht-Pic in gemeinsamen Objekten wird wahrscheinlich keine ernsthaften Probleme verursachen, obwohl dies zu mehr RAMs führen kann, wenn die Bibliothek über Prozesse und/oder Benutzer hinweg häufig verwendet wird.

Update (4/17)

Ich habe seitdem die Ursache von entdeckt etwas Von den Abstürken, die ich zuvor gesehen hatte. Um zu zeigen:

/*header.h*/
#include <map>
typedef std::map<std::string,std::string> StringMap;
StringMap asdf;

/*file1.cc*/
#include "header.h"

/*file2.cc*/
#include "header.h"

int main( int argc, char** argv ) {
  for( int ii = 0; ii < argc; ++ii ) {
    asdf[argv[ii]] = argv[ii];
  }

  return 0;
}

... dann:

$ g++ file1.cc -shared -PIC -o libblah1.so
$ g++ file1.cc -shared -PIC -o libblah2.so
$ g++ file1.cc -shared -PIC -o libblah3.so
$ g++ file1.cc -shared -PIC -o libblah4.so
$ g++ file1.cc -shared -PIC -o libblah5.so

$ g++ -zmuldefs file2.cc -Wl,-{L,R}$(pwd) -lblah{1..5} -o fdsa
#     ^^^^^^^^^
#     This is the evil that made it possible
$ args=(this is the song that never ends);
$ eval ./fdsa $(for i in {1..100}; do echo -n ${args[*]}; done)

Dieses bestimmte Beispiel stürzt möglicherweise nicht ab, aber es ist im Grunde die Situation, die im Code dieser Gruppe existiert hat. Wenn es tut Crash Es wird wahrscheinlich im Destruktor sein, normalerweise ein doppelter Fehler.

Viele Jahre zuvor fügten sie hinzu -zmuldefs zu ihrem Build, um multiplizierende Symbolfehler loszuwerden. Der Compiler gibt Code zum Ausführen von Konstruktoren/Zerstörern auf globalen Objekten aus. -zmuldefs zwingt sie, im Speicher am selben Ort zu leben, aber es führt immer noch die Konstrukteure/Zerstörer für die Exe und jede Bibliothek mit dem beleidigenden Header aus-daher die doppelfreie.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top