Wenn ich etwas auf meinem Ubuntu Lucid 10.04-PC kompiliere, wird es mit glibc verknüpft. Lucid verwendet 2.11 von glibc. Wenn ich diese Binärdatei auf einem anderen PC mit einem älteren glibc ausführe, schlägt der Befehl fehl und sagt, dass es kein glibc 2.11 gibt ...
Soweit ich weiß, verwendet glibc die Symbolversionierung. Kann ich gcc zwingen, eine Verknüpfung mit einer bestimmten Symbolversion herzustellen?
In meiner konkreten Verwendung versuche ich, eine gcc cross toolchain für ARM zu kompilieren.
Antworten:
Sie haben Recht, dass glibc die Symbolversionierung verwendet. Wenn Sie neugierig sind, wird hier die in glibc 2.1 eingeführte Implementierung der Symbolversionierung beschrieben , die eine Erweiterung des hier beschriebenen Versionsschemas für Symbole von Sun darstellt .
Eine Möglichkeit besteht darin, Ihre Binärdatei statisch zu verknüpfen. Dies ist wahrscheinlich die einfachste Option.
Sie können Ihre Binärdatei auch in einer Chroot-Build-Umgebung oder mit einem glibc- new => glibc- old- Cross-Compiler erstellen .
Laut dem Blog-Beitrag http://www.trevorpounds.com Linking to Older Versioned Symbols (glibc) ist es möglich, die Verknüpfung eines Symbols mit einem älteren zu erzwingen, solange es mit demselben
.symver
Pseudo gültig ist -op, das in erster Linie zum Definieren versionierter Symbole verwendet wird. Das folgende Beispiel ist ein Auszug aus dem Blog-Beitrag .Im folgenden Beispiel wird der Realpath von glibc verwendet, es wird jedoch sichergestellt, dass er mit einer älteren Version 2.2.5 verknüpft ist.
quelle
libc.a
existiert weiterhin, glibc unterstützt dies in einigen Fällen, obwohl es nicht empfohlen wird (Drepper) . Sie werden Probleme mit nicht trivialen Programmen haben, insbesondere mit allem, was NSS verwendet (Problemumgehung in den FAQ ).Verknüpfung mit -static . Wenn Sie mit -static verknüpfen, bettet der Linker die Bibliothek in die ausführbare Datei ein, sodass die ausführbare Datei größer ist. Sie kann jedoch auf einem System mit einer älteren Version von glibc ausgeführt werden, da das Programm anstelle der des Systems eine eigene Bibliothek verwendet .
quelle
Setup 1: Kompilieren Sie Ihren eigenen glibc ohne dedizierten GCC und verwenden Sie ihn
Da es unmöglich erscheint, nur mit Hacks zur Symbolversionierung zu arbeiten, gehen wir noch einen Schritt weiter und kompilieren glibc selbst.
Dieses Setup funktioniert möglicherweise und ist schnell, da nicht die gesamte GCC-Toolchain neu kompiliert wird, sondern nur glibc.
Aber es ist nicht zuverlässig , wie es Host - C - Laufzeit - Objekte verwendet wie
crt1.o
,crti.o
undcrtn.o
von glibc zur Verfügung gestellt. Dies wird erwähnt unter: https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location Diese Objekte führen eine frühe Einrichtung durch, auf die sich glibc stützt. Ich wäre also nicht überrascht, wenn die Dinge wunderbar abstürzen würden und unglaublich subtile Wege.Eine zuverlässigere Einrichtung finden Sie unter Setup 2 unten.
Erstellen Sie glibc und installieren Sie es lokal:
Setup 1: Überprüfen Sie den Build
test_glibc.c
Kompilieren und ausführen mit
test_glibc.sh
:Das Programm gibt Folgendes aus:
Befehl angepasst von https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location, aber
--sysroot
fehlgeschlagen mit:also habe ich es entfernt.
ldd
Die Ausgabe bestätigt, dass dieldd
und Bibliotheken, die wir gerade erstellt haben, tatsächlich wie erwartet verwendet werden:Die
gcc
Debug-Ausgabe der Kompilierung zeigt, dass meine Host-Laufzeitobjekte verwendet wurden, was, wie bereits erwähnt, schlecht ist, aber ich weiß nicht, wie ich es umgehen soll, z. B. enthält es:Setup 1: Glibc ändern
Jetzt ändern wir glibc mit:
Dann kompilieren Sie glibc neu und installieren Sie es erneut. Kompilieren Sie unser Programm neu und führen Sie es erneut aus:
und wir sehen
hacked
einige Male wie erwartet gedruckt.Dies bestätigt weiter, dass wir tatsächlich den von uns kompilierten Glibc verwendet haben und nicht den Host.
Getestet unter Ubuntu 18.04.
Setup 2: Crosstool-NG makelloses Setup
Dies ist eine Alternative zur Einrichtung 1, und es ist die richtige Setup ich bisher erreicht habe: alles korrekt ist, soweit ich beobachten kann, einschließlich der C - Laufzeit - Objekte wie
crt1.o
,crti.o
, undcrtn.o
.In diesem Setup kompilieren wir eine vollständige dedizierte GCC-Toolchain, die den gewünschten glibc verwendet.
Der einzige Nachteil dieser Methode ist, dass der Build länger dauert. Aber ich würde kein Produktionssetup mit weniger riskieren.
crosstool-NG ist eine Reihe von Skripten, die alles von der Quelle für uns herunterladen und kompilieren, einschließlich GCC, glibc und binutils.
Ja, das GCC-Build-System ist so schlecht, dass wir dafür ein separates Projekt benötigen.
Dieses Setup ist nur nicht perfekt, da Crosstool-NG das Erstellen der ausführbaren Dateien ohne zusätzliche
-Wl
Flags nicht unterstützt , was sich seltsam anfühlt, da wir GCC selbst erstellt haben. Aber alles scheint zu funktionieren, daher ist dies nur eine Unannehmlichkeit.Holen Sie sich Crosstool-NG und konfigurieren Sie es:
Die einzige obligatorische Option, die ich sehen kann, besteht darin, sie an Ihre Host-Kernel-Version anzupassen, um die richtigen Kernel-Header zu verwenden. Finden Sie Ihre Host-Kernel-Version mit:
was mir zeigt:
also
menuconfig
mache ich:Operating System
Version of linux
also wähle ich:
Dies ist die erste gleiche oder ältere Version. Es muss älter sein, da der Kernel abwärtskompatibel ist.
Jetzt können Sie bauen mit:
und warten Sie nun etwa dreißig Minuten bis zwei Stunden für die Zusammenstellung.
Setup 2: optionale Konfigurationen
Das
.config
, mit dem wir generiert haben,./ct-ng x86_64-unknown-linux-gnu
hat:Um dies zu ändern,
menuconfig
tun Sie Folgendes:C-library
Version of glibc
Speichern Sie die
.config
und fahren Sie mit dem Build fort.Oder, wenn Sie Ihre eigene glibc Quelle verwenden möchten, zB glibc aus dem aktuellen git zu verwenden, gehen Sie wie folgt aus :
Paths and misc options
Try features marked as EXPERIMENTAL
: auf true setzenC-library
Source of glibc
Custom location
: Sag jaCustom location
Custom source location
: Zeigen Sie auf ein Verzeichnis, das Ihre Glibc-Quelle enthältwo glibc geklont wurde als:
Setup 2: Testen Sie es
Sobald Sie die gewünschte Toolchain erstellt haben, testen Sie sie mit:
Alles scheint wie in Setup 1 zu funktionieren, außer dass jetzt die richtigen Laufzeitobjekte verwendet wurden:
Setup 2: Fehlgeschlagener effizienter Glibc-Neukompilierungsversuch
Mit Crosstool-NG scheint dies nicht möglich zu sein, wie unten erläutert.
Wenn Sie nur neu erstellen;
Dann werden Ihre Änderungen am benutzerdefinierten Glibc-Quellspeicherort berücksichtigt, aber alles wird von Grund auf neu erstellt, sodass es für die iterative Entwicklung unbrauchbar wird.
Wenn wir es tun:
Es gibt einen schönen Überblick über die Build-Schritte:
Daher sehen wir, dass es glibc-Schritte gibt, die mit mehreren GCC-Schritten verflochten sind, insbesondere
libc_start_files
vorhercc_core_pass_2
, was wahrscheinlich der teuerste Schritt zusammen mit istcc_core_pass_1
.Um nur einen Schritt zu erstellen, müssen Sie zuerst die
.config
Option "Zwischenschritte speichern" in der Option für den ersten Build festlegen:Paths and misc options
Debug crosstool-NG
Save intermediate steps
und dann können Sie versuchen:
aber leider
+
erforderlich wie unter https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536 angegebenund im Grunde macht der Wiederaufbau immer noch zu langsam, um für die Entwicklung machbar zu sein, und ich sehe nicht, wie ich dies überwinden kann, ohne Crosstool-NG zu patchen.
Darüber hinaus
libc
schien das Starten ab dem Schritt nicht erneut über die Quelle zu kopierenCustom source location
, was diese Methode weiter unbrauchbar machte.Bonus: stdlibc ++
Ein Bonus, wenn Sie auch an der C ++ - Standardbibliothek interessiert sind: Wie kann ich die GCC libstdc ++ C ++ - Standardbibliotheksquelle bearbeiten und neu erstellen?
quelle
musl-libc
ist eine weitere Option für die C-Laufzeit.Meiner Meinung nach wurde die faulste Lösung (insbesondere wenn Sie sich nicht auf die neuesten C / C ++ - Funktionen oder die neuesten Compilerfunktionen verlassen) noch nicht erwähnt.
Bauen Sie einfach auf dem System mit dem ältesten GLIBC auf, den Sie noch unterstützen möchten.
Dies ist heutzutage mit Technologien wie chroot, KVM / Virtualbox oder Docker ziemlich einfach, selbst wenn Sie eine so alte Distribution nicht direkt auf einem PC verwenden möchten. Im Detail empfehle ich die folgenden Schritte, um eine maximale tragbare Binärdatei Ihrer Software zu erstellen:
Wählen Sie einfach Ihr Gift aus Sandbox / Virtualisierung / ... was auch immer und verwenden Sie es, um sich ein virtuelles älteres Ubuntu LTS zu besorgen und mit dem darin enthaltenen gcc / g ++ zu kompilieren. Dadurch wird Ihr GLIBC automatisch auf den in dieser Umgebung verfügbaren GLIBC beschränkt.
Vermeiden Sie es, von externen Bibliotheken außerhalb der grundlegenden zu abhängig zu sein: Sie sollten beispielsweise bodennahe Systemdaten wie glibc, libGL, libxcb / X11 / wayland-Dinge, libasound / libpulseaudio und möglicherweise GTK + dynamisch verknüpfen, wenn Sie diese verwenden, ansonsten aber vorzugsweise statisch externe verknüpfen libs / versende sie mit, wenn du kannst. Insbesondere meistens in sich geschlossene Bibliotheken wie Bildlader, Multimedia-Decoder usw. können bei anderen Distributionen weniger Bruch verursachen (Bruch kann beispielsweise verursacht werden, wenn sie nur irgendwo in einer anderen Hauptversion vorhanden sind), wenn Sie sie statisch versenden.
Mit diesem Ansatz erhalten Sie eine alte GLIBC-kompatible Binärdatei ohne manuelle Symboländerungen, ohne eine vollständig statische Binärdatei (die bei komplexeren Programmen möglicherweise nicht funktioniert, weil glibc dies hasst und Lizenzprobleme für Sie verursachen kann) und ohne Einstellung Erstellen Sie eine benutzerdefinierte Toolchain, eine benutzerdefinierte Glibc-Kopie oder was auch immer.
quelle