Linux-Binary läuft nicht: glibc oder musl?
Bei GLIBC_2.34 not found hat der Build-Host die Mindestversion festgelegt. Prüfen Sie die Anforderungen der Binary und wählen Sie eine von vier portablen Lösungen.
Warum eine Linux-Binärdatei auf einem älteren Server nicht ausgeführt wird
Eine portable Linux-Binärdatei ist schwierig zu erstellen, weil glibc, die GNU-C-Bibliothek, Kompatibilität nur in eine Richtung gewährleistet. Eine alte Binärdatei läuft weiterhin mit einer neuen glibc. Eine neue Binärdatei läuft nicht mit einer alten glibc. Die Maschine, auf der Sie kompilieren, legt die untere Grenze für jede Maschine fest, auf der Sie die Binärdatei bereitstellen.
Die Fehlermeldung nennt die exakt benötigte Version:
./mytool: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.38' not found (required by ./mytool)Nichts ist beschädigt und nichts ist falsch konfiguriert. Der dynamische Loader hat ein Versions-Tag gelesen, das in der Binärdatei gespeichert ist, im System-libc nach diesem Tag gesucht, es dort nicht gefunden und den Programmstart verweigert. Die Datei erneut herunterzuladen und chmod +x auszuführen, ändert nichts, weil die Anforderung in der Datei selbst gespeichert ist. Sie müssen entweder die Erstellung der Binärdatei ändern oder ändern, was Sie ausliefern.
Was die glibc-Symbolversionierung tatsächlich bewirkt
Jede von glibc exportierte Funktion trägt ein Versions-Tag. printf innerhalb von libc.so.6 ist tatsächlich printf@@GLIBC_2.2.5. Wenn glibc das Verhalten oder die ABI (Application Binary Interface) einer Funktion ändert, ersetzt glibc die alte Funktion nicht. Der alte Code bleibt unter dem alten Tag erhalten, und der neue Code kommt unter einem neuen Tag hinzu. Ein einzelnes libc.so.6 enthält dadurch gleichzeitig mehrere Versionen desselben Symbols. Ein Binary aus dem Jahr 2009 findet den Tag aus dem Jahr 2009 weiterhin vor. Deshalb funktioniert die Vorwärtskompatibilität so zuverlässig.
Beim Linken wird festgehalten, welche Version verwendet wurde. Ihr Binary erhält einen Abschnitt .gnu.version_r, der sinngemäß angibt: „Ich benötige GLIBC_2.38 aus libc.so.6.“ Eine ältere libc hatte diesen Tag nie. Deshalb beendet der Loader den Vorgang, bevor main ausgeführt wird. Es gibt kein Fallback. Ein Fallback würde bedeuten, dass das Programm stillschweigend eine andere Funktion erhält als die, gegen die es kompiliert wurde.
Der häufigste Auslöser ist seit 2021 glibc 2.34. Diese Version führte libpthread und libdl in libc zusammen und verschob __libc_start_main, die Funktion, die jedes C-Programm startet, auf den Tag GLIBC_2.34. Ein Hello-World-Programm, das auf einer Distribution mit glibc 2.34 oder neuer kompiliert wurde, benötigt deshalb GLIBC_2.34, obwohl der Quellcode keine moderne Funktion aufruft. Deshalb trat das Problem plötzlich bei Anwendern auf, deren eigener Code seit Jahren unverändert war.
Welche glibc-Version liefert meine Distribution aus?
The data behind this chart
[
{
"distro": "CentOS 7",
"glibc": 2.17
},
{
"distro": "RHEL 8",
"glibc": 2.28
},
{
"distro": "Ubuntu 20.04",
"glibc": 2.31
},
{
"distro": "Debian 11",
"glibc": 2.31
},
{
"distro": "RHEL 9",
"glibc": 2.34
},
{
"distro": "Ubuntu 22.04",
"glibc": 2.35
},
{
"distro": "Debian 12",
"glibc": 2.36
},
{
"distro": "Ubuntu 24.04",
"glibc": 2.39
},
{
"distro": "Debian 13",
"glibc": 2.41
}
]Das sind die Versionen, die die einzelnen Distributionen in ihren eigenen Paketquellen ausliefern, wie von den Distributionen veröffentlicht und im August 2026 aktuell. CentOS 7 hat das Ende seiner Lebensdauer längst erreicht. Es bleibt in der Liste, weil geerbte Server weiterhin damit betrieben werden. Prüfen Sie jedes System mit ldd --version. Der Befehl gibt die glibc-Version in der ersten Zeile aus. Alternativ können Sie getconf GNU_LIBC_VERSION verwenden.
Lesen Sie diese 9 Zeilen als Stufenfolge. Wenn Sie auf Debian 13 mit glibc 2.41 bauen, läuft das Ergebnis auf keinem älteren System als Debian 13. Wenn Sie auf Ubuntu 20.04 mit glibc 2.31 bauen, läuft derselbe Quellcode auf jeder darüber aufgeführten Zeile, einschließlich des Debian-13-Systems. Der älteste Server, den Sie unterstützen müssen, ist der einzige relevante Build-Host. Die von Ihnen standardisierte Distribution legt daher die ABI-Untergrenze für alles fest, was Sie dafür kompilieren. Diese Entscheidung sollten Sie treffen, bevor die Serverflotte existiert, zusammen mit den anderen Abwägungen bei der Auswahl des Betriebssystems für Ihren VPS.
Wie finde ich die minimale glibc-Version, die ein Binary benötigt?
Lesen Sie die Information aus der Datei aus. Das funktioniert mit jeder Datei, auch mit einem Binary, das Sie von einem Anbieter ohne Build-Dokumentation erhalten haben.
objdump -T ./mytool | grep -o 'GLIBC_[0-9.]*' | sort -Vu | tail -5Die letzte Zeile gibt die Mindestversion an. Wenn objdump fehlt, installieren Sie das Paket binutils. Wenn Sie auf diesem System nichts installieren können, liefert strings -a ./mytool | grep -o 'GLIBC_[0-9.]*' | sort -Vu | tail -5 ein nahezu gleichwertiges Ergebnis, weil die Tags als einfache Zeichenfolgen in der Datei gespeichert sind.
readelf -V ./mytool zeigt dieselbe Anforderung strukturiert an. Suchen Sie nach dem Block mit der Überschrift Version needs section '.gnu.version_r'. Er enthält pro Tag eine Zeile mit Name: GLIBC_x.y und gruppiert die Einträge unter der Bibliothek, die den jeweiligen Tag bereitstellen muss.
Um herauszufinden, welche Funktionsmenge die Mindestversion bestimmt, suchen Sie nach dem Tag: objdump -T ./mytool | grep GLIBC_2.38. Häufig handelt es sich um ein einzelnes Symbol, das Sie unter Umständen vermeiden können. Wenn objdump -T überhaupt keine Ausgabe erzeugt, ist das Binary statisch gelinkt. Es besitzt daher keine dynamische Symboltabelle und keine auszugebende Versionsanforderung.
Was file und readelf -d über eine übergebene Binärdatei aussagen
file zeigt die Architektur und den Link-Typ in einer Zeile.
file ./mytoolEin gewöhnlicher glibc-Build sieht so aus:
ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=..., for GNU/Linux 3.2.0, not strippedEin statischer Build meldet statically linked und nennt keinen Interpreter. Ein musl-Build nennt einen anderen:
ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-x86_64.so.1, ...Der Interpreter ist das entscheidende Feld. Dabei handelt es sich um den dynamischen Loader, den der Kernel vor Ihrem Programm ausführt. Dieser exakte Pfad muss auf dem Zielsystem vorhanden sein. /lib/ld-musl-x86_64.so.1 ist auf einem Debian- oder Ubuntu-Server nicht vorhanden, sofern dort niemand musl installiert hat.
readelf -d ./mytool listet die benötigten Shared Libraries der Binärdatei nach Namen auf:
Dynamic section at offset 0x2d58 contains 27 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libssl.so.3]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000001d (RUNPATH) Library runpath: [$ORIGIN/../lib]Jeder Eintrag NEEDED ist eine zwingend erforderliche Abhängigkeit, die über den Soname aufgelöst wird. libssl.so.3 gehört zu OpenSSL 3. Diese Binärdatei wird daher auf einem Server nicht geladen, auf dem nur libssl.so.1.1 vorhanden ist. Der Soname ist der Grund dafür: Ein anderer Soname bedeutet eine absichtlich inkompatible ABI. RUNPATH teilt dem Loader mit, wo er zuerst suchen soll. $ORIGIN wird zum Verzeichnis erweitert, in dem sich die Binärdatei befindet. So findet ein eigenständiges Bundle seine eigenen Bibliotheken.
Führen Sie ldd nicht für eine Binärdatei aus, der Sie nicht vertrauen. Unter glibc kann ldd Abhängigkeiten auflösen, indem das Programm unter dem Loader ausgeführt wird. Dadurch kann eine schädliche Datei Code ausführen. readelf und objdump lesen dagegen nur Bytes. Prüfen Sie zuvor, ob der Download tatsächlich der vom Projekt veröffentlichten Datei entspricht. Die Prüfung eines Downloads anhand der veröffentlichten Prüfsumme ist der einzige Schritt, der Ihnen sagt, wessen Bytes Sie in Händen halten.
Die tatsächlich auftretenden Fehler und ihre Bedeutung
Der Loader nennt eine GLIBC-Version, die er nicht finden kann. Die Binärdatei wurde gegen eine neuere glibc-Version kompiliert, als auf dem Zielsystem vorhanden ist. Eine nachträgliche Installation auf dem Zielsystem behebt das Problem nicht sicher. Wählen Sie eine der vier folgenden Optionen.
Die Shell meldet No such file or directory für eine Datei, die eindeutig vorhanden ist. Es fehlt der Interpreter, nicht die Binärdatei. execve gibt ENOENT zurück, wenn der Loader-Pfad im ELF-Header fehlt, und die Shell gibt die einzige verfügbare Meldung aus. Führen Sie file aus und lesen Sie den Interpreter-Pfad ab. Eine musl-gelinkte Binärdatei auf einem Server, der ausschließlich glibc verwendet, verursacht genau dieses Symptom.
cannot execute binary file: Exec format error bedeutet, dass die Architektur nicht übereinstimmt: eine x86-64-Binärdatei auf einem arm64-Server oder umgekehrt. Die erste Zeile der Ausgabe von file zeigt, welche Architektur vorliegt.
error while loading shared libraries: libssl.so.3: cannot open shared object file bedeutet, dass eine NEEDED-Bibliothek fehlt oder unter einem anderen soname vorhanden ist. Installieren Sie das passende Paket der Distribution. Die Paketnamen unterscheiden sich zwischen den Distributionfamilien. Übersetzen Sie daher eine apt-Zeile aus einer README, bevor Sie sie kopieren. Die entsprechenden Befehle für dnf und apt zeigen diese Zuordnung.
Ein einzelnes Segmentation fault bei einem musl-Build, der unter glibc problemlos läuft. Meistens ist die Thread-Stackgröße die Ursache. Diese wird unter Option 2 behandelt.
Vier Möglichkeiten, eine portable Linux-Binärdatei bereitzustellen
Jede Option hat reale Nachteile. Wählen Sie anhand dessen, was Ihr Programm zur Laufzeit benötigt, und nicht danach, welche Option am saubersten klingt.
Option 1: Auf der ältesten unterstützten Distribution bauen
Die unspektakulärste Antwort und meistens die richtige. Kompilieren Sie innerhalb eines Container-Images der ältesten Distribution, die Sie unterstützen möchten. Der Linker kann nur Tags aufzeichnen, die diese alte glibc tatsächlich enthält. Dadurch wird die Untergrenze auf diese Version gesetzt, während die Binärdatei eine normale dynamische Binärdatei bleibt und das gesamte Verhalten von glibc beibehält.
docker run --rm -v "$PWD:/src" -w /src ubuntu:20.04 sh -c 'apt-get update && apt-get install -y build-essential && make'Die Ausgabe läuft auf glibc 2.31 und allen höheren Versionen. Verlassen Sie sich nicht auf Annahmen, sondern prüfen Sie dies: Führen Sie den objdump -T-Einzeiler von weiter oben für das Ergebnis aus und prüfen Sie, ob der höchste Tag dem erwarteten Wert entspricht.
Der Nachteil ist die Toolchain. Ein altes Basis-Image enthält auch einen alten Compiler. Das führt zu Problemen, wenn Ihr Code einen aktuellen C++-Standard benötigt. Go und Rust umgehen dieses Problem weitgehend, weil ihre Toolchains unabhängig von den Distributionspaketen im Container installiert werden. Für C und C++ können Sie einen neueren Compiler aus dem eigenen Toolchain-Kanal der Distribution hinzufügen oder eines der manylinux-Images verwenden. Diese Images existieren genau dafür, eine veraltete glibc mit einem aktuellen GCC zu kombinieren. Der gebündelte C-Compiler von Zig kann ebenfalls direkt auf eine ausgewählte glibc zielen, wie in zig cc -target x86_64-linux-gnu.2.28. Damit erhalten Sie dieselbe Untergrenze, ohne ein altes Image dauerhaft bereithalten zu müssen.
Option 2: Statisch gegen musl linken
musl ist eine kleine C-Bibliothek, die für statisches Linken entwickelt wurde. Ein statisches musl-Binary enthält seine eigene libc, benötigt keinen Interpreter und läuft auf jedem Linux-Kernel der passenden Architektur. So werden die meisten Downloads einzelner Tools erstellt.
sudo apt install -y musl-tools
musl-gcc -static -O2 hello.c -o hello
file ./hellofile sollte jetzt statically linked lauten und kein Interpreter-Feld enthalten. Für Rust fügen Sie das Target hinzu und bauen dagegen:
rustup target add x86_64-unknown-linux-musl
cargo build --release --target x86_64-unknown-linux-muslGo benötigt dies nicht. Mit CGO_ENABLED=0 go build ist das Ergebnis bereits statisch und linkt überhaupt keine libc.
NSS-Auflösungen ändern sich. glibc löst Benutzer und Hostnamen über NSS (Name Service Switch) auf. Dabei lädt sie libnss_*-Module mit dlopen, während das Programm läuft. Eine statisch gelinkte glibc kann dies nicht. Der Linker warnt mit folgendem Wortlaut:
warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linkingmusl umgeht diese Warnung, weil es NSS überhaupt nicht implementiert. Es verfügt über einen eigenen Resolver und liest /etc/resolv.conf und /etc/hosts direkt. Auf einem gewöhnlichen VPS ist das unproblematisch und einfacher. Auf einem Host, auf dem Konten oder Namen aus LDAP oder SSSD stammen, sieht Ihr Binary diese nicht, während alle anderen Programme auf dem Host darauf zugreifen können. Der Resolver von musl ist außerdem jünger als der von glibc: Der TCP-Fallback für DNS-Antworten mit mehr als 512 Bytes wurde in musl 1.2.4 im Jahr 2023 eingeführt. Builds gegen ältere musl-Versionen schneiden daher große Antworten ab.
dlopen funktioniert nicht. In einem statischen musl-Binary ist dlopen ein Stub, der immer fehlschlägt. Alles, was zur Laufzeit Code lädt, ist damit ausgeschlossen: Plugin-Systeme, PAM-Module, GPU-Treiber und die eigenen iconv-Zeichensatzmodule von glibc. Wenn Ihr Programm dlopen benötigt, kommt statisches Linken nicht infrage. Sie benötigen dann eine der drei anderen Optionen.
Sicherheitsupdates werden zu Ihrer Aufgabe. Ein dynamisch gelinktes Binary übernimmt eine Korrektur in der libc, sobald der Server sein Paket-Upgrade ausführt. Ein statisches Binary tut das nie. Wenn ein CVE-Eintrag (Common Vulnerabilities and Exposures) für Ihre libc oder für ein von Ihnen gebündeltes statisches OpenSSL veröffentlicht wird, müssen Sie das Binary neu bauen und verteilen. Jede bereits bereitgestellte Kopie bleibt verwundbar, bis jemand die Datei ersetzt. Dokumentieren Sie, was Sie gelinkt haben. Auf dem Zielsystem kann nichts einem Administrator mitteilen, dass Ihr Binary eine Bibliothek aus der Zeit vor zwei Jahren enthält.
Die Lizenz ändert sich. glibc steht unter der LGPL. Statisches Linken löst die Relinking-Pflicht der LGPL aus: Sie müssen Empfängern alles bereitstellen, was sie benötigen, um Ihr Programm gegen eine andere glibc-Version neu zu linken. musl steht unter der MIT-Lizenz und enthält keine solche Bedingung. Das ist der Hauptgrund, warum Projekte für einzelne Binary-Dateien musl statt statischer glibc auswählen.
Zwei Laufzeitunterschiede verursachen schwer verständliche Abstürze. Der Standard-Thread-Stack von musl ist 128 KiB groß, bei glibc sind es 8 MiB. Code, der einen großen Puffer auf dem Thread-Stack anlegt, verursacht daher einen Segmentation Fault ohne Meldung und ohne Logeintrag. Legen Sie die Größe mit pthread_attr_setstacksize explizit fest oder verschieben Sie den Puffer auf den Heap. Der Allocator von musl wurde außerdem auf kleine Größe und vorhersehbares Verhalten ausgelegt, nicht auf viele Threads, die gleichzeitig Speicher reservieren. Programme mit hoher Speicherallokationslast und vielen Threads können daher messbar langsamer laufen. Benchmarken Sie Ihre eigene Arbeitslast, statt sich auf den Ruf einer der beiden Bibliotheken zu verlassen.
Option 3: Loader und Bibliotheken bündeln
Legen Sie die Bibliotheken zusammen mit dem passenden Loader neben der Binärdatei ab. Starten Sie das Programm anschließend über diesen Loader.
./ld-linux-x86-64.so.2 --library-path ./lib ./mytoolDamit diese Einstellung dauerhaft gilt, schreiben Sie die Pfade mit patchelf in die Datei:
patchelf --set-interpreter "$PWD/lib/ld-linux-x86-64.so.2" --set-rpath '$ORIGIN/lib' ./mytoolEine Regel entscheidet darüber, ob dies funktioniert: Der Loader und libc.so.6 müssen aus demselben glibc-Build stammen. Sie bilden ein zusammengehöriges Paar. Wenn Sie den Loader des Hosts mit einer gebündelten libc kombinieren, stürzt das Programm beim Start ab, statt eine verständliche Fehlermeldung auszugeben. Bündeln Sie beide Komponenten oder keine.
AppImage ist eine verpackte Variante dieses Musters. Die Nutzdaten liegen in einem squashfs-Image, das von einer kleinen Runtime eingebunden wird. Eine wichtige Eigenschaft wird häufig übersehen: Ein AppImage bündelt glibc nicht. Daher schlägt ein auf einer aktuellen Distribution erstelltes AppImage auf einem alten Server weiterhin mit demselben Versionsfehler fehl. Die Empfehlungen von AppImage lauten, auf der ältesten unterstützten Basis zu bauen. Damit ist AppImage ein Bereitstellungsformat, das auf Option 1 aufsetzt, und kein Ersatz dafür.
Auf einem Headless-Server benötigt AppImage FUSE (Filesystem in Userspace), um seine Nutzdaten einzubinden. Ein minimales VPS-Image enthält FUSE häufig nicht. Die Fehlermeldung nennt libfuse.so.2. Mit ./App.AppImage --appimage-extract-and-run können Sie das Einbinden vollständig überspringen. Dabei werden die Nutzdaten in ein temporäres Verzeichnis entpackt und von dort ausgeführt.
Option 4: Container-Image bereitstellen
Verschieben Sie den gesamten Userland zusammen mit dem Programm. Das Image enthält seine eigene libc. Deshalb ist die glibc des Hosts nicht mehr relevant. Nur der Kernel und die Architektur müssen kompatibel sein. Dies ist die unkomplizierteste Option. Sie beseitigt die gesamte Problemklasse. Deshalb wird so viel Serversoftware auf diese Weise verteilt. Docker auf einem VPS ausführen ist der übliche Weg, das Image zu verwenden.
Der Kernel des Hosts setzt weiterhin eine Grenze. Neuere glibc-Versionen verwenden neuere Systemaufrufe. Ein alter Container-Host kann diese blockieren: glibc 2.34 und später verwenden clone3. Ältere Standard-seccomp-Profile lehnen diesen Systemaufruf ab. Das äußert sich durch einen sofortigen Fehler mit Operation not permitted, ohne dass glibc irgendwo erwähnt wird. Eine Aktualisierung der Container-Laufzeitumgebung auf dem Host behebt das Problem. Die Blockierung befindet sich im Syscall-Filter der Laufzeitumgebung und nicht im Kernel.
Die Kosten sind üblich. Auf dem Zielsystem werden eine Container-Laufzeitumgebung und die erforderlichen Berechtigungen benötigt. Der Download wächst von einer Datei auf mehrere Dutzend oder mehrere hundert Megabyte. Sie sind nun für ein Basis-Image und dessen Patch-Zeitplan verantwortlich. Damit kehrt die Sicherheitsarbeit, die Sie in Option 2 vermieden haben, in Form von Image-Neuerstellungen zurück. Für einen dauerhaft laufenden Dienst ist das ein vertretbarer Kompromiss. Für ein Kommandozeilenprogramm, das jemand einmal ausführt, ist es das nicht.
Welche Option sollten Sie wählen?
- Ein internes Tool für Server, die Sie kontrollieren und auf denen dieselbe Distribution läuft: Erstellen Sie das Programm dynamisch auf dieser Distribution und belassen Sie es dabei.
- Eine einzelne Datei, die Unbekannte herunterladen und ausführen: Verwenden Sie statisches musl, wenn das Programm weder
dlopennoch NSS-gestützte Lookups benötigt. - Ein Programm mit Plugins oder GPU-Zugriff: Bleiben Sie bei einer dynamischen Erstellung, verwenden Sie eine alte Basis und nutzen Sie Option 3 für die Auslieferung.
- Ein dauerhaft laufender Dienst auf einem Rechner, auf dem bereits eine Laufzeitumgebung vorhanden ist: Liefern Sie das Image aus.
Unabhängig von Ihrer Entscheidung sollten Sie sie dokumentieren und überprüfen. Die glibc des Build-Hosts ist nun Bestandteil Ihres Release-Prozesses. Wird eine Build-Maschine von einem LTS-Release auf das nächste aktualisiert, steigt die Mindestanforderung unbemerkt. Dadurch fallen Benutzer aus, bei denen das Programm im letzten Monat noch funktioniert hat. Pinnen Sie das Build-Image anhand des Tags. Prüfen Sie außerdem den höchsten GLIBC_-Tag in der Ausgabe als Build-Schritt. So schlägt die Prüfung in Ihrer Pipeline fehl und nicht erst im Terminal eines anderen Benutzers.
FAQ
Warum erhalte ich auf meinem Server „version GLIBC_2.38 not found“?
Die Binärdatei wurde auf einem System mit einer neueren glibc kompiliert als auf Ihrem Server installiert ist. Die Symbolversionierung von glibc bietet nur Vorwärtskompatibilität: Alte Binärdateien laufen mit einer neuen glibc, neue Binärdateien jedoch nicht mit einer alten glibc. Der Loader benötigt den exakten Versions-Tag, der in der Datei gespeichert ist. Eine ältere libc hatte diesen Tag nie. Eine sichere Installation auf dem Server behebt das Problem nicht. Erstellen Sie die Binärdatei auf einer älteren Basis neu, stellen Sie einen statischen musl-Build bereit, bündeln Sie die Bibliotheken mit dem passenden Loader oder stellen Sie ein Container-Image bereit.
Wie finde ich heraus, welche glibc-Version eine Binärdatei benötigt?
Lesen Sie die Versions-Tags mit objdump -T ./mytool | grep -o 'GLIBC_[0-9.]*' | sort -Vu | tail -5 aus der Datei aus. Die letzte Zeile enthält die niedrigste glibc-Version, mit der die Datei geladen werden kann. readelf -V ./mytool zeigt dieselben Anforderungen im Abschnitt .gnu.version_r, gruppiert nach der Bibliothek, die sie bereitstellen muss. Wenn objdump -T nichts ausgibt, ist die Binärdatei statisch gelinkt und hat überhaupt keine glibc-Anforderung. Vergleichen Sie das Ergebnis mit der Version Ihres Servers, die ldd --version ausgibt.
Ist eine musl-Binärdatei langsamer als eine glibc-Binärdatei?
Das hängt von der Arbeitslast ab. Die verlässliche Antwort liefert eine Messung. Eine statische musl-Binärdatei startet schneller, weil kein Loader ausgeführt werden muss und beim Start keine Relokationen erforderlich sind. Der Allocator von musl ist dagegen auf geringe Größe und vorhersehbares Verhalten ausgelegt, nicht auf viele Threads, die gleichzeitig Speicher reservieren. Außerdem enthält musl weniger manuell optimierte Routinen für Zeichenketten und Speicher als glibc. Thread-Programme mit vielen Speicherreservierungen oder Zeichenkettenoperationen können daher spürbar langsamer sein. Benchmarken Sie Ihr eigenes Programm auf Ihrem eigenen Server, bevor Sie eine der beiden Aussagen übernehmen.
Warum meldet bash „No such file or directory“ für eine vorhandene Datei?
Die fehlende Datei ist der dynamische Loader, nicht Ihre Binärdatei. Der Kernel liest den Interpreter-Pfad aus dem ELF-Header und gibt ENOENT zurück, wenn dieser Pfad nicht vorhanden ist. Die Shell zeigt diese Meldung an, weil ihr keine genauere Meldung zur Verfügung steht. Führen Sie file ./mytool aus und lesen Sie das Feld interpreter. Wenn dort /lib/ld-musl-x86_64.so.1 auf einem Debian- oder Ubuntu-Server steht, ist die Binärdatei gegen musl gelinkt, während das System glibc verwendet. Sie benötigen daher den musl-kompatiblen Download oder einen statischen Build.
Kann ich libc.so.6 von einem neueren Server kopieren, um das Problem zu beheben?
Nein. libc.so.6 und ld-linux-x86-64.so.2 gehören als abgestimmtes Paar zu einem glibc-Build. Jeder Prozess auf dem System verwendet diese Dateien. Das Überschreiben der Systemkopie kann daher dazu führen, dass der Server nichts mehr ausführen kann, einschließlich der Werkzeuge, die Sie zum Rückgängigmachen der Änderung benötigen. Wenn Sie eine einzelne neuere Binärdatei auf einem alten Host ausführen müssen, entpacken Sie die neuere glibc in ein privates Verzeichnis und starten Sie das Programm über den eigenen Loader mit --library-path. Diese Vorgehensweise betrifft nur diesen Prozess. Die Binärdatei gegen die ältere glibc neu zu erstellen, bleibt die Lösung, die Sie nicht sechs Monate später überrascht.