Frage

Wenn ich etwas auf meinem Ubuntu Lucid 10.04 PC kompilieren wird es gegen glibc verlinkt sind. Lucid verwendet 2.11 von glibc. Wenn ich diese binären auf einem anderen PC mit einem älteren glibc ausführen, schlägt sagen Sie den Befehl gibt es keine glibc 2.11 ...

Soweit ich glibc Anwendungen Symbol kennen Versionierung. Kann ich gcc Link gegen eine bestimmte Symbol Version erzwingen?

In meiner konkreten Anwendung ich versuche, einen gcc Quertoolchain für ARM zu kompilieren.

War es hilfreich?

Lösung

Sie sind richtig, dass glibc Anwendungen Symbol Versionierung. Wenn Sie neugierig sind, Implementierung der Symbol Versionierung in glibc eingeführt 2.1 hier und ist ein Erweiterung von Sun Symbol Versionsschema beschrieben hier .

Eine Option ist zu statisch Ihre binäres zu verknüpfen. Dies ist wahrscheinlich die einfachste Option.

Sie können auch Ihre binär in einer chroot-Build-Umgebung oder mit einem glibc- neue => glibc- alt Cross-Compiler bauen.

Nach dem http: // www. trevorpounds.com Blogeintrag Verknüpfung mit älterem Versionierte Symbolen (glibc) ist es möglich, ein beliebiges Symbol, um zu zwingen, gegen eine älteren so lange verbunden werden, wie es gültig ist, indem mit der den gleichen .symver pseudo-op, die für die Definition versioniert Symbole in erster Linie verwendet wird. Das folgende Beispiel ist ein Auszug aus dem Blog Post .

Das folgende Beispiel der Verwendung von Glibc realpath macht, sondern sorgt dafür, dass es gegen eine ältere Version 2.2.5 verbunden ist.

#include <limits.h>
#include <stdlib.h>
#include <stdio.h>

__asm__(".symver realpath,realpath@GLIBC_2.2.5");
int main()
{
    const char* unresolved = "/lib64";
    char resolved[PATH_MAX+1];

    if(!realpath(unresolved, resolved))
        { return 1; }

    printf("%s\n", resolved);

    return 0;
}

Andere Tipps

Link mit -static . Wenn Sie einen Link mit -static der Linker die Bibliothek innerhalb der ausführbaren bettet, so wird die ausführbare Datei größer sein, aber es kann mit einer älteren Version von glibc auf einem System ausgeführt werden, da das Programm verwendet, wird es selbst ist Bibliothek statt der des Systems.

Setup 1: Ihre eigene glibc ohne dedizierten GCC kompilieren und es verwenden,

Da es unmöglich scheint nur mit dem Symbol Versionierung Hacks zu tun, gehen wir einen Schritt weiter und Kompilierung glibc uns selbst.

Diese Einstellung könnte funktionieren und ist schnell, da es nicht den ganzen GCC-Toolchain nicht neu kompilieren, nur glibc.

Aber es ist nicht zuverlässig, wie es Host-C-Laufzeitobjekte wie crt1.o verwendet, crti.o und crtn.o von glibc zur Verfügung gestellt. Dies wird erwähnt unter: https://sourceware.org/glibc/ wiki / Testing / baut? action = Rückruf & u = 21 # Compile_against_glibc_in_an_installed_location Diese Objekte tun früh Setup, dass glibc auf beruht, so würde ich nicht überrascht sein, wenn die Dinge in wunderbar und awesomely subtile Weise abgestürzt ist.

Für eine zuverlässigere Einrichtung finden Setup 2 unten.

Build glibc und lokal installieren:

export glibc_install="$(pwd)/glibc/build/install"

git clone git://sourceware.org/git/glibc.git
cd glibc
git checkout glibc-2.28
mkdir build
cd build
../configure --prefix "$glibc_install"
make -j `nproc`
make install -j `nproc`

Setup 1: Überprüfen Sie die Build

test_glibc.c

#define _GNU_SOURCE
#include <assert.h>
#include <gnu/libc-version.h>
#include <stdatomic.h>
#include <stdio.h>
#include <threads.h>

atomic_int acnt;
int cnt;

int f(void* thr_data) {
    for(int n = 0; n < 1000; ++n) {
        ++cnt;
        ++acnt;
    }
    return 0;
}

int main(int argc, char **argv) {
    /* Basic library version check. */
    printf("gnu_get_libc_version() = %s\n", gnu_get_libc_version());

    /* Exercise thrd_create from -pthread,
     * which is not present in glibc 2.27 in Ubuntu 18.04.
     * https://stackoverflow.com/questions/56810/how-do-i-start-threads-in-plain-c/52453291#52453291 */
    thrd_t thr[10];
    for(int n = 0; n < 10; ++n)
        thrd_create(&thr[n], f, NULL);
    for(int n = 0; n < 10; ++n)
        thrd_join(thr[n], NULL);
    printf("The atomic counter is %u\n", acnt);
    printf("The non-atomic counter is %u\n", cnt);
}

Kompilieren und Ausführen mit test_glibc.sh:

#!/usr/bin/env bash
set -eux
gcc \
  -L "${glibc_install}/lib" \
  -I "${glibc_install}/include" \
  -Wl,--rpath="${glibc_install}/lib" \
  -Wl,--dynamic-linker="${glibc_install}/lib/ld-linux-x86-64.so.2" \
  -std=c11 \
  -o test_glibc.out \
  -v \
  test_glibc.c \
  -pthread \
;
ldd ./test_glibc.out
./test_glibc.out

Das Programm gibt die erwarteten:

gnu_get_libc_version() = 2.28
The atomic counter is 10000
The non-atomic counter is 8674

Befehl angepasst von https://sourceware.org/glibc / wiki / Testing / baut action = Rückruf & u = 21 # Compile_against_glibc_in_an_installed_location aber --sysroot machte es nicht mit:

cannot find /home/ciro/glibc/build/install/lib/libc.so.6 inside /home/ciro/glibc/build/install

, damit ich es entfernt wird.

ldd Ausgabe bestätigt, dass die ldd und Bibliotheken, dass wir gerade gebaut haben tatsächlich verwendet werden, wie erwartet:

+ ldd test_glibc.out
        linux-vdso.so.1 (0x00007ffe4bfd3000)
        libpthread.so.0 => /home/ciro/glibc/build/install/lib/libpthread.so.0 (0x00007fc12ed92000)
        libc.so.6 => /home/ciro/glibc/build/install/lib/libc.so.6 (0x00007fc12e9dc000)
        /home/ciro/glibc/build/install/lib/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007fc12f1b3000)

Die gcc Compilation Debug-Ausgabe zeigt, dass meine Host-Laufzeitobjekte verwendet wurden, was schlecht ist, wie bereits erwähnt, aber ich weiß nicht, wie es zu umgehen, zum Beispiel es enthält:

COLLECT_GCC_OPTIONS=/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crt1.o

Setup 1: modify glibc

Lassen Sie uns jetzt modify glibc mit:

diff --git a/nptl/thrd_create.c b/nptl/thrd_create.c
index 113ba0d93e..b00f088abb 100644
--- a/nptl/thrd_create.c
+++ b/nptl/thrd_create.c
@@ -16,11 +16,14 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */

+#include <stdio.h>
+
 #include "thrd_priv.h"

 int
 thrd_create (thrd_t *thr, thrd_start_t func, void *arg)
 {
+  puts("hacked");
   _Static_assert (sizeof (thr) == sizeof (pthread_t),
                   "sizeof (thr) != sizeof (pthread_t)");

Dann recompile und installieren glibc und recompile und starten unser Programm:

cd glibc/build
make -j `nproc`
make -j `nproc` install
./test_glibc.sh

und wir sehen hacked ein paar Mal gedruckt, wie erwartet.

Dies bestätigt weiter, dass wir die glibc tatsächlich genutzt, dass wir zusammengestellt und nicht der Host ein.

Getestet auf Ubuntu 18.04.

Setup 2: crosstool-NG ursprünglichen Setup

Dies ist eine Alternative zur Einrichtung 1, und es ist die richtige Setup ich bisher erreicht habe: alles so weit richtig ist, wie ich beobachten kann, einschließlich den C-Laufzeitobjekte wie crt1.o, crti.o und crtn.o

In diesem Aufbau werden wir einen vollen gewidmet GCC-Toolchain kompilieren, die die glibc verwendet, dass wir wollen.

Der einzige Nachteil dieser Methode ist, dass die Build wird länger dauern. Aber ich würde nicht einen Produktionsaufbau mit etwas riskieren weniger.

crosstool-NG eine Sammlung von Skripten ist, dass Downloads und kompiliert alles von der Quelle für uns, einschließlich GCC, glibc und binutils.

Ja, das GCC-Build-System ist so schlecht, dass wir ein separates Projekt dafür brauchen.

Dieses Setup nur nicht perfekt, weil crosstool-NG unterstützt nicht die ausführbaren Dateien Aufbau ohne zusätzliche -Wl Flaggen , die seltsam fühlt, da wir GCC selbst gebaut haben. Aber alles scheint zu funktionieren, so dass dies nur eine Unannehmlichkeit ist.

Get crosstool-NG und konfiguriert es:

git clone https://github.com/crosstool-ng/crosstool-ng
cd crosstool-ng
git checkout a6580b8e8b55345a5a342b5bd96e42c83e640ac5
export CT_PREFIX="$(pwd)/.build/install"
export PATH="/usr/lib/ccache:${PATH}"
./bootstrap
./configure --enable-local
make -j `nproc`
./ct-ng x86_64-unknown-linux-gnu
./ct-ng menuconfig

Die einzige obligatorische Option, dass ich sehen kann, macht es Host-Kernel-Version passen die richtigen Kernel-Header zu verwenden. Finden Sie Ihre Host-Kernel-Version mit:

uname -a

, die zeigt mir:

4.15.0-34-generic

so in menuconfig ich tun:

  • Operating System
    • Version of linux

so ich wählen:

4.14.71

, die die erste gleich oder ältere Version ist. Es hat älter sein, da der Kernel rückwärts kompatibel ist.

Jetzt können Sie bauen mit:

env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`

und jetzt etwa 30 Minuten warten, bis zwei Stunden für die Kompilierung.

Setup 2: optionale Konfigurationen

Die .config, dass wir mit ./ct-ng x86_64-unknown-linux-gnu erzeugt hat:

CT_GLIBC_V_2_27=y

Um das zu ändern, in menuconfig tun:

  • C-library
  • Version of glibc

Speichern der .config, und fahren Sie mit dem Build.

Oder, wenn Sie möchten, dass Ihre eigene glibc Quelle verwenden, z.B. Gebrauch glibc aus dem aktuellen git, gehen Sie Beispiel :

  • Paths and misc options
    • Try features marked as EXPERIMENTAL: auf true
  • C-library
    • Source of glibc
      • Custom location: sagen wir ja
      • Custom location
        • Custom source location: Punkt in ein Verzeichnis mit Ihrer glibc Quelle

Dabei gilt glibc geklont wurde wie:

git clone git://sourceware.org/git/glibc.git
cd glibc
git checkout glibc-2.28

Setup 2: Test it out

Sobald Sie haben er Toolchain gebaut, dass Sie wollen, testen Sie es mit:

#!/usr/bin/env bash
set -eux
install_dir="${CT_PREFIX}/x86_64-unknown-linux-gnu"
PATH="${PATH}:${install_dir}/bin" \
  x86_64-unknown-linux-gnu-gcc \
  -Wl,--dynamic-linker="${install_dir}/x86_64-unknown-linux-gnu/sysroot/lib/ld-linux-x86-64.so.2" \
  -Wl,--rpath="${install_dir}/x86_64-unknown-linux-gnu/sysroot/lib" \
  -v \
  -o test_glibc.out \
  test_glibc.c \
  -pthread \
;
ldd test_glibc.out
./test_glibc.out

Alles scheint zu funktionieren wie in Setup 1, mit der Ausnahme, dass jetzt die richtigen Laufzeitobjekte verwendet:

COLLECT_GCC_OPTIONS=/home/ciro/crosstool-ng/.build/install/x86_64-unknown-linux-gnu/bin/../x86_64-unknown-linux-gnu/sysroot/usr/lib/../lib64/crt1.o

Setup 2: failed effiziente glibc Neuübersetzung Versuch

Es scheint nicht möglich, mit crosstool-NG, wie weiter unten erläutert wird.

Wenn Sie nur re-build;

env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`

Sie Ihre Änderungen an der benutzerdefinierten glibc Quellenort werden berücksichtigt, aber es baut alles von Grund auf neu, es unbrauchbar für die iterative Entwicklung.

Wenn wir das tun:

./ct-ng list-steps

Es gibt einen schönen Überblick über die Build-Schritte:

Available build steps, in order:
  - companion_tools_for_build
  - companion_libs_for_build
  - binutils_for_build
  - companion_tools_for_host
  - companion_libs_for_host
  - binutils_for_host
  - cc_core_pass_1
  - kernel_headers
  - libc_start_files
  - cc_core_pass_2
  - libc
  - cc_for_build
  - cc_for_host
  - libc_post_cc
  - companion_libs_for_target
  - binutils_for_target
  - debug
  - test_suite
  - finish
Use "<step>" as action to execute only that step.
Use "+<step>" as action to execute up to that step.
Use "<step>+" as action to execute from that step onward.

wir also sehen, dass es glibc Schritte mit mehreren GCC Schritte verflochten, insbesondere libc_start_files kommt vor cc_core_pass_2, die mit cc_core_pass_1 wahrscheinlich der teuerste Schritt zusammen ist.

Um nur einen Schritt zu bauen, müssen Sie zuerst die "Save Zwischenschritte" in .config Option für die intial build gesetzt:

  • Paths and misc options
    • Debug crosstool-NG
      • Save intermediate steps

und dann können Sie versuchen:

env -u LD_LIBRARY_PATH time ./ct-ng libc+ -j`nproc`

aber leider benötigt, um die + wie bei erwähnt: https: //github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536

  

Beachten Sie jedoch, dass bei einem Zwischenschritt Neustart setzt das Installationsverzeichnis in den Zustand in diesem Schritt hatte. Das heißt, erhalten Sie einen neu erstellten libc haben - aber keine endgültigen Compiler mit diesem libc gebaut (und somit keine Compiler-Bibliotheken wie libstdc ++ entweder)

.

und im Grunde immer noch die zu langsam macht Wiederaufbau für Entwicklung möglich zu sein, und ich sehe nicht, wie dies zu überwinden, ohne crosstool-NG Patchen.

Darüber hinaus ist aus dem libc Schritt beginnen schien nicht wieder die Quelle kopieren Sie von Custom source location, weiter diese Methode unbrauchbar zu machen.

Bonus: stdlibc ++

Ein Bonus, wenn Sie auch in der C interessiert sind ++ Standard-Bibliothek: Wie zu bearbeiten und neu bauen die GCC libstdc ++ C ++ Standard-Bibliothek Quelle?

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