GCC verknüpft libc static und einige andere Bibliotheken dynamisch, überarbeitet?

Lesezeit: 10 Minuten

Benutzer-Avatar
AttributedTensorField

Folgende Fragen sind relevant, beantworten aber nicht meine Frage:

Verlinkung teilweise statisch und teilweise dynamisch in GCC

Verknüpfen einer dynamischen Bibliothek mit einer statischen Bibliothek, die mit anderen statischen Bibliotheken verknüpft ist

GCC: Statisches Linken nur einiger Bibliotheken

Statischer Link der gemeinsam genutzten Bibliotheksfunktion in gcc

Ich habe vorhin eine sehr ähnliche Frage gestellt, aber da die vorherige Frage, die von mir gestartet wurde, im Kommentarbereich etwas überladen und nicht vollständig beantwortet wurde (aber ich habe sie als beantwortet markiert, da es eine gute Anstrengung war und sie zumindest teilweise beantwortet hat), werde ich es tun eine neue Frage stellen. Die Frage ist speziell, wie man libc statisch verlinkt, während man andere Bibliotheken (zB libm) dynamisch verlinkt. Dies wurde in der ersten Frage vorgeschlagen, was nicht möglich ist, ist das wahr? Wenn ja, wäre es sehr interessant zu wissen, warum nicht.

Ist es überhaupt möglich, dies zu tun? Jemand hat einen Kommentar gemacht (der aus irgendeinem Grund entfernt wurde, vielleicht war er falsch?), dass es möglich ist, aber es muss dann Auch existiert eine dynamisch gelinkte Version von libc, da sie von der dynamischen Bibliothek benötigt wird (z. B. dynamische libm erfordert dynamische libc (?)).

Das ist in Ordnung für mich, aber es ist mir nicht klar, wie ich GCC anweisen soll, dies zu tun, dh in libc sowohl statisch als auch dynamisch zu verknüpfen. Wie mache ich das (ich habe ein paar Versuche unternommen, einige werden später in der Frage gezeigt)? Oder gibt es eine andere Möglichkeit, das zu tun, was ich will?

Wir sehen zunächst, dass durch einfaches Ausführen von gcc test.c -lm alles wie folgt dynamisch eingebunden wird:

$ gcc test.c -lm
$ ldd a.out 
        linux-vdso.so.1 (0x00007fffb37d1000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f3b0eeb6000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f3b0eb10000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f3b0f1b0000)

Um nur libm als statisch zu verknüpfen, während libc dynamisch bleibt, können wir Folgendes tun (wie Z-Boson in einer der oben genannten Fragen betonte):

$ gcc test.c /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libm.a

$ ldd a.out 
        linux-vdso.so.1 (0x00007fff747ff000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f09aaa0c000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f09aadb2000)

Der Versuch, mit demselben Verfahren libc static und libm dynamic zu verknüpfen, scheint jedoch nicht zu funktionieren:

$ gcc test.c /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a -lm
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie
collect2: error: ld returned 1 exit status

Was bedeutet diese Fehlermeldung?

Einige andere Versuche (die meisten waren auch in meiner ersten Frage enthalten):

$ gcc test.c /usr/lib64/libc.a
linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib64/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie
urned 1 exit status
$ gcc test.c -Wl,-Bdynamic -lm -Wl,-Bstatic -lc
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status
$ gcc -Wl,-Bdynamic -lm -Wl,-Bstatic -lc test.c
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status
$ gcc -Wl,-Bstatic -lc -Wl,-Bdynamic -lm test.c
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie
collect2: error: ld returned 1 exit status
$ gcc test.c /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.so -lm
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie
collect2: error: ld returned 1 exit status
$ gcc test.c /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.so /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a -lm

Beachten Sie, dass der letzte erfolgreich kompiliert/verknüpft wurde. Allerdings wurde libc nicht statisch eingebunden, sondern nur dynamisch, also ist es ein weiterer fehlgeschlagener Versuch.

Das Testprogramm ist einfach das folgende:

$ cat test.c 
#include <stdio.h>
#include <math.h>

int main(int argc, char **argv)
{
        int i;
        int result;

        for(i = 0; i < 65535; i++) {
                result = sin(i);
        }

        return 0;
}

Bearbeiten:

Ich habe auch Statifier und Hermelin ausprobiert, wie in dieser Frage vorgeschlagen:

Statischer Link der gemeinsam genutzten Bibliotheksfunktion in gcc

Beides funktioniert nicht.

  • Was ist das Problem, das Sie zu lösen versuchen? Ich meine auf einer höheren Ebene, nicht “Ich möchte statisch verlinken”. Vielleicht können wir das Problem lösen.

    – Johannes Zwinck

    9. Oktober 2014 um 11:56 Uhr

  • libm Links zu libc – das kann Teil des Problems sein (siehe ldd /usr/lib64/libm.so).

    – el.pescado – нет войне

    9. Oktober 2014 um 12:13 Uhr

  • @John Zwinck, es ist nicht trivial, ich versuche zu zeigen, dass ein ROP-basierter Exploit unter bestimmten Umständen gegen Intel MPX möglich ist, aber es erfordert, dass libmpx (das nur in dynamisch verknüpfter Form existiert, kein Quellcode verfügbar ist, soweit ich weiß) wird dynamisch eingebunden und libc wird statisch eingebunden. Wenn dies jedoch nicht möglich ist, wäre es auf jeden Fall interessant zu wissen, warum nicht, und ich würde nach einem anderen Ansatz suchen.

    – Zugeschriebenes TensorField

    9. Oktober 2014 um 12:58 Uhr

  • @el.pescado, ja, das ist höchstwahrscheinlich zumindest ein Teil des Problems, es wurde kurz im Kommentarbereich darauf hingewiesen, bevor der Kommentar in der anderen Frage verschwand.

    – Zugeschriebenes TensorField

    9. Oktober 2014 um 12:59 Uhr

  • Benötigen Sie die ganz von libc statisch gelinkt, oder nur ein paar spezifische Funktionen?

    – ams

    9. Oktober 2014 um 14:06 Uhr

Benutzer-Avatar
ams

Grundsätzlich ist Ihr erster Ansatz der richtige Weg, dies zu tun:

gcc test.c libc.a -lm

Nachdem gcc die impliziten Bibliotheken hinzugefügt hat, sieht es (konzeptionell) so aus:

gcc crt1.o test.c libc.a -lm -lc -lgcc -lc

Das bedeutet also, dass alle libc-Funktionen, die von entweder aufgerufen werden crt1.o oder test.c wird eingezogen libc.a und statisch verknüpft, während alle aufgerufenen Funktionen einzig und allein aus libm oder libgcc wird dynamisch gelinkt (aber es wird die statischen Funktionen wiederverwenden, wenn libm etwas bereits Eingezogenes aufruft).

Der Linker beginnt immer bei der Datei/Bibliothek ganz links und arbeitet nach rechts; es geht nie zurück. .c und .o Dateien werden unbedingt eingebunden, aber .a Dateien und -l Optionen werden nur verwendet, um bereits referenzierte, aber noch nicht definierte Funktionen zu finden. Daher ist eine Bibliothek auf der linken Seite sinnlos (und -lc muss da zweimal erscheinen -lc kommt drauf an -lgccund -lgcc kommt drauf an -lc). Linkreihenfolge ist wichtig!

Leider scheinen Sie durch einen möglichen Fehler vereitelt worden zu sein strcmp (oder besser gesagt in der libc, die enthält strcmp): das STT_GNU_IFUNC thing ist eine clevere Funktion, die es ermöglicht, mehrere Versionen einer Funktion einzubinden und die optimale zur Laufzeit auszuwählen, basierend auf der verfügbaren Hardware. Ich bin mir nicht sicher, aber es sieht so aus, als ob diese Funktion nur in einem PIE-Build (Position Independent Executable) oder einem Shared-Library-Build verfügbar ist.

Warum das in einer statischen sein würde libc.a ist mir ein Rätsel, aber es gibt eine einfache Problemumgehung: Implementieren Sie Ihre eigene strcmp (Eine einfache, langsame Implementierung besteht nur aus ein paar Zeilen C) und verlinke sie Vor libc.a.

gcc test.c mystrcmp.c libc.a -lm

Alternativ können Sie die Funktionen aus extrahieren libc.a die Sie wirklich wollen, und verknüpfen Sie nur diese statisch:

ar x libc.a
gcc test.c somefile.o -lm

ar ist zu .a Dateien, als tar ist zu .tar Dateien, obwohl die Verwendung des Befehls etwas variiert, daher extrahiert dieses Beispiel die .o Dateien aus der .a Datei und verknüpft sie dann explizit.

  • Fantastisch! Genau die Antwort, die ich gesucht/erhofft hatte. Ich bin tatsächlich (beim Googeln) auf Beiträge gestoßen, in denen dies mit einem Fehler zusammenhängt, aber ich habe es verworfen, da die Beiträge ein paar Jahre alt waren.

    – Zugeschriebenes TensorField

    9. Oktober 2014 um 15:52 Uhr

  • Nebenbei (die Frage wurde sehr gut beantwortet), bekomme ich leider “a.out: Fehler beim Laden von Shared Libraries: RTLD_NEXT used in code not dynamically loading”, wenn ich dies mit der MPX-Bibliothek (libmpx) mache. Ich werde mich aber noch näher damit befassen.

    – Zugeschriebenes TensorField

    9. Oktober 2014 um 16:08 Uhr

  • Ich denke, man kann mit Sicherheit sagen, dass dies keine gut getestete Anordnung ist. Es kann gut sein, dass es viele Fehler gibt. Vielleicht sogar ein Hingucker.

    – ams

    9. Oktober 2014 um 16:22 Uhr

  • @AttributedTensorField, ich freue mich, dass Sie diese Frage weiterverfolgt haben. Der Grund, warum ich versucht habe, Ihre Frage zu beantworten, ist, dass ich eine gemeinsam genutzte Bibliothek erstellt habe und keine Abhängigkeiten in der Bibliothek selbst haben wollte. Als ich die Bibliothek auf einem älteren Linux-Rechner verwendete, stellte ich fest, dass sie aufgrund dieser Abhängigkeiten abstürzte. Es war einfach, diese gemeinsam genutzte Bibliothek ohne Abhängigkeiten mit MSVC zu erstellen, aber mit GCC war es ein großer Schmerz. Auf Linux-Systemen kompiliere ich die Bibliothek für jedes System neu (was ohne Root-Zugriff nicht immer einfach ist). Man hat das Gefühl, dass GCC nicht möchte, dass Sie die Dinge statisch machen.

    – Z-Boson

    10. Oktober 2014 um 8:26 Uhr


  • @Zboson Das ist ziemlich genau; Statische Binärdateien haben Probleme, und es gibt bestimmte Funktionen, die eine moderne Glibc nicht statisch machen möchte (dh die libc.a-Version wird dlopen eine Bibliothek). FWIW, die übliche Lösung für das Portabilitätsproblem besteht darin, Bibliotheken aus einem alten System zu verwenden – sie funktionieren normalerweise auf neueren Systemen, aber nicht umgekehrt. RHEL5 ist im Moment eine gute Option.

    – ams

    10. Oktober 2014 um 8:43 Uhr

Benutzer-Avatar
Z-Boson

Basierend auf der Antwort von ams habe ich Folgendes getan

mystrcmp.c

int strcmp(const char *s1, const char *s2) {
}

Kompilieren

gcc -c test.c
gcc -c mystrcmp.c

Setup-Dateien

ln -s `gcc -print-file-name=crt1.o`
ln -s `gcc -print-file-name=crti.o`
ln -s `gcc -print-file-name=crtn.o`
ln -s `gcc -print-file-name=libgcc_eh.a`
ln -s `gcc -print-file-name=libc.a`
ln -s `gcc -print-file-name=libm.so`

Verknüpfung

ld -m elf_x86_64 -o math crt1.o crti.o test.o mystrcmp.o libc.a libgcc_eh.a libc.a libm.so -dynamic-linker /lib64/ld-linux-x86-64.so.2 crtn .Ö

Dies verbindet und läuft korrekt. Jedoch, ldd zeigt an

linux-vdso.so.1 =>  (0x00007fff51911000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f8182470000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f81820a9000)
/lib64/ld-linux-x86-64.so.2 (0x00007f8182793000)

Es scheint so dynamisch libm erfordert Dynamik libc. Eigentlich ist das einfach zu zeigen

ldd libm.so berichtet

linux-vdso.so.1 =>  (0x00007fff20dfe000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fcaf74fe000)
/lib64/ld-linux-x86-64.so.2 (0x00007fcaf7bed000)

Es ist also unmöglich, auf libm.so zu verlinken, ohne auch libc.so zu verlinken, es sei denn, Sie schaffen es, libm ohne die Abhängigkeit von libc zu kompilieren.

  • Ich frage mich, ob Sie tatsächlich alle erforderlichen .o-Dateien eingezogen haben, bevor libc.so angefordert wurde.

    – Xennex81

    10. Juni 2017 um 17:06 Uhr

1379840cookie-checkGCC verknüpft libc static und einige andere Bibliotheken dynamisch, überarbeitet?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy