Z jakiej wersji biblioteki C korzysta mój system?

43

Jak mogę z całą pewnością stwierdzić, jakiej biblioteki użytkownika C używa mój system? Możliwe powody, dla których potrzebne są te informacje, to:

  • Jest gigantyczny pakiet źródłowy, który rozważam do pobrania, który z pewnością wykona odpowiednie kontrole i wyświetli minimalną wersję biblioteki, ale wolę oszczędzić sobie potencjalnego problemu, sprawdzając najpierw, czy zadziała.

  • Martwię się o kompatybilność ABI z niektórymi plikami binarnymi stron trzecich, które chcę wypróbować poza systemem zarządzania pakietami systemu.

  • Mam pakiet źródłowy, którego dokumentacja wspomina o potrzebie minimalnej wersji biblioteki mojego systemu, ale proces kompilacji nie wykonuje żadnych kontroli.

  • Buduję cross-kompilator ukierunkowany na konkretny system i nie chcę ryzykować problemów z kompatybilnością .

Złotowłosa
źródło
Dlaczego nie spróbować? Nie wiem, czy wersja mówi ci wszystko; co z łatkami? A może dystrakcje ostrożnie zmieniają ABI? Czy nie jest problem, czy eksportowane symbole zostały rozwiązane, czy coś w tym rodzaju?
Faheem Mitha
Dobre odpowiedzi, ale nikt nie mówi, jak to zrobić na komputerze Mac, gdzie nie ma ldd. Nie jestem pewien, czy otool --versionmożna uznać, że daje te same informacje.
dubiousjim
@dubiousjim Ktoś mógł; po prostu nie ja, ponieważ nie jestem użytkownikiem komputera Mac. W tym miejscu możesz być zmuszony zapytać o to konkretnie - częścią problemu może być to, że ludzie zazwyczaj nie używają zwykłego C na OSX? Ale jestem pewien, że będzie regularny, który wie. Możesz również zamieścić link do tego na czacie i zobaczyć, co się stanie, ale prawdopodobnie nowe, bardziej szczegółowe pytanie byłoby lepsze.
goldilocks

Odpowiedzi:

50

Systemy GNU / Linux zwykle używają albo glibc (rodzina Fedora / Redhat, Arch) lub jego bliskiego kuzyna, eglibc (rodzina Debian / Ubuntu); ponieważ eglibc jest teraz ponownie łączony w glibc ( patrz Oddział EGLIBC 2.19 utworzony w dziale „Wiadomości” ), w niedalekiej przyszłości wszyscy będą ponownie glibc.

Najłatwiejszym sposobem sprawdzenia dokładnej wersji jest zapytanie ldd, która wersja jest dostarczana z biblioteką C.

W Fedorze 20:

> ldd --version
ldd (GNU libc) 2.18

To glibc 2.18.

W systemie Raspbian (port Debian 7 dla ARMv6 Broadcom SoC):

> ldd --version
ldd (Debian EGLIBC 2.13-38+rpi2) 2.13

To jest eglibc 2.13.

Jeśli z jakiegokolwiek powodu zmieszałeś i dopasowałeś niektóre części lub w inny sposób nie jesteś pewien ldd, możesz bezpośrednio zapytać bibliotekę C.

> whereis libc.so
libc: /usr/lib64/libc.a /usr/lib64/libc.so /usr/share/man/man7/libc.7.gz

Żaden z nich nie jest wykonywalny, ale dostarczają wskazówek, gdzie go znaleźć.

> $(find /usr/lib64/ -executable -name "*libc.so*") --version
GNU C Library (GNU libc) stable release version 2.18, by Roland McGrath et al.

Jednak niekoniecznie jest to takie łatwe, ponieważ biblioteka C nie musi się gdzieś whereisznajdować, aby ją znaleźć.

> whereis libc.so
libc: /usr/share/man/man7/libc.7.gz

Niestety strona podręcznika nie podaje numeru wersji. lddwciąż jest przydatny, ponieważ każdy działający, dynamicznie połączony plik wykonywalny w systemie (np. prawie wszystko w /usr/bin) będzie łączył się z biblioteką C.

> ldd /usr/bin/touch
    /usr/lib/arm-linux-gnueabihf/libcofi_rpi.so (0xb6eed000)
    librt.so.1 => /lib/arm-linux-gnueabihf/librt.so.1 (0xb6ed0000)
    libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0xb6da1000)
    /lib/ld-linux-armhf.so.3 (0xb6efb000)
    libpthread.so.0 => /lib/arm-linux-gnueabihf/libpthread.so.0 (0xb6d82000)

libc.so.6 jest na trzeciej linii.

> /lib/arm-linux-gnueabihf/libc.so.6 --version
GNU C Library (Debian EGLIBC 2.13-38+rpi2) stable release version 2.13, by Roland McGrath et al.
Złotowłosa
źródło
Co sprawia, że ​​system GNU / Linux jest „normalny”? Co z dystrybucjami używającymi musla ?
Elliott Frisch
1
@ElliottFrisch Miało być stosowane do GNU / Linux, jak w „normal GNU / Linux” (przymiotnik, rzeczownik), ponieważ mogą istnieć (są, jestem pewien) systemy, które nie używają (e) glibc, ale robią użyj reszty stosu GNU (bash, binutils itp.). Rozważałbym te „niezwykłe” systemy GNU / Linux. Ale usunąłem „normalne” i zmieniłem na „Systemy GNU / Linux zwykle używają ...”. Uwaga Celowo pozostawiłem pytanie otwarte specyfikacja systemu WRT (nie ma linuksa, GNU lub tagu glibc), więc jeśli chcesz dodać odpowiedź dotyczącą dowolnego systemu odpowiedniego dla U&L, zrób to.
goldilocks
1
Kiedy znalazłem go tak, jak pokazałeś i zapytałem o wersję, wydrukowałem również dostępne rozszerzenia! (w moim przypadku kody pośredniczące, crypt, libidn, natywne wątki i powiązanie) i odnosiły się do ABI: libc ABI: UNIKALNE IFUNC.
Debian używa /lib/`uname -m`*ścieżki. Tak przenośny sposób byłoby: find /lib/`uname -m`* /usr/lib* -executable -name "*libc.so*" | xargs --version. Dziękuję za miłe wyjaśnienie.
pevik
@pevik: Źle, na ramię To /lib/arm-linux-gnueabihf/libc.so.6, a nie /lib/armv7l/libc.so.6
rozterce
14

System nie jest w rzeczywistości ograniczony do jednej biblioteki C. Większość jednak używa przede wszystkim tylko jednego, który będzie również domyślnym kompilatorem. A ponieważ pobierasz kod źródłowy w celu kompilacji, właśnie o to się martwisz.

Zacznij od trywialnego programu:

#include <stdio.h>
int main() {
    printf("Hello, world\n");
    return 0;
}

skompiluj go za pomocą kompilatora, którego będziesz używać dla kodu źródłowego, a następnie użyj, lddaby dowiedzieć się, gdzie jest biblioteka C:

$ ldd ./libc-test 
        linux-vdso.so.1 (0x00007fff2e5fe000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8c8ad98000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f8c8b171000)

Masz teraz ścieżkę do biblioteki C. Możesz to sprawdzić w menedżerze pakietów, aby znaleźć pakiet (np. dpkg -S /lib/x86_64-linux-gnu/libc.so.6Lub rpm -q -f /lib/x86_64-linux-gnu/libc.so.6).

Przynajmniej w przypadku eglibc / glibc możesz go uruchomić:

$ /lib/x86_64-linux-gnu/libc.so.6  
GNU C Library (Debian EGLIBC 2.18-4) stable release version 2.18, by Roland McGrath et al.
Copyright (C) 2013 Free Software Foundation, Inc.

Wreszcie, możesz sprawdzić, czy możesz uzyskać wskazówki objdump -p /lib/x86_64-linux-gnu/libc.so.6, przeglądając sekcję definicji wersji :

Version definitions:
1 0x01 0x0865f4e6 libc.so.6
2 0x00 0x09691a75 GLIBC_2.2.5
3 0x00 0x09691a76 GLIBC_2.2.6
21 0x00 0x06969197 GLIBC_2.17
        GLIBC_2.16 
22 0x00 0x06969198 GLIBC_2.18
        GLIBC_2.17 
23 0x00 0x0963cf85 GLIBC_PRIVATE
        GLIBC_2.18 

Zwróć uwagę, że symbol GLIBC_2.18 ma najnowszy numer wersji spośród wymienionych symboli, a wersja biblioteki to rzeczywiście 2.18. Jest jednak eglibc (ma być binarnie kompatybilny z glibc 2.18, więc używa tych samych wersji symboli).

Możesz także spróbować stringsdowiedzieć się czegoś na ten temat. Będziesz chciał określić dłuższą minimalną długość ( -n) lub użyj grep, aby wyszukać coś:

$ strings  /lib/x86_64-linux-gnu/libc.so.6 | grep 'version [0-9]'
$ strings  /lib/x86_64-linux-gnu/libc.so.6 | grep -iC1 'copyright'

oba działają dla tego eglibc.

UWAGA: Narzędzie pakietu Debian dpkg-shlibdepsużywa objdumppod maską, wraz z przechowywanymi informacjami o symbolach w pakietach bibliotek Debiana, w celu określenia minimalnych wersji zależności wymaganych przez binarne pakiety Debiana podczas kompilacji. Zasadniczo patrzy na symbole eksportowane przez binarny pakiet Debian, a następnie znajduje minimalne wersje bibliotek, które zawierają te symbole.

derobert
źródło
9

Oczywistą odpowiedzią, choć nie najbardziej wyczerpującą, jest sprawdzenie menedżera pakietów, np

rpm -qi glibc
dpkg -l libc6

(Niestety, glibc nie ma .pcpliku pkconfig , więc nie jest programem uruchamiającym pkgconfig --modversion glibc.) Zobacz także doskonałą getconfsugestię @ Gnouc .

Najprostszym przypadkiem, z gcc + glibc, i tym, którego najczęściej używam jako pierwszego, jest po prostu wykonanie libc.so, jak opisano w niektórych innych odpowiedziach tutaj. Nie trzeba przekazywać żadnych argumentów, domyślnie wyświetla ona swoją wersję. To działa aż do glibc-2.1 (seg-fault glibc-2.0, choć dawno temu można było sprawdzić (obecnie wycofany) glibcbugskrypt, aby potwierdzić wersję). Ta metoda działa również z najnowszymi (> 0.9.15) wersjami musl-libc (które właśnie weszły 1.0 dzisiaj, 20 marca). Nie działa z uClibc, powoduje awarie.

Jednym prostym sposobem na dokładne określenie, co gcczamierzasz zrobić, jest kompilacja:

#include <gnu/libc-version.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
    printf("%s %s\n",gnu_get_libc_version(),gnu_get_libc_release());
    printf("glibc v%i %i.%i\n",__GNU_LIBRARY__,__GLIBC__,__GLIBC_MINOR__);
    return 0;
}

(z glibc, <stdio.h>zawiera <features.h>który określa odpowiednie makra glibc musisz <gnu/libc-version.h>do deklaracji funkcji.)

Łapie to bardziej złożone przypadki (wiele bibliotek libc i / lub wiele kompilatorów), zakładając oczywiście, że używasz właściwego kompilatora (i flag). (Podejrzewam, że nie rozróżnia jednak właściwego eglibc od glibc).

Jeśli masz pewność, że używasz glibc (lub eglibc) ld, potwierdzi również wersję (przepraszam, to nie jest poprawne).

Jeśli __GNU_LIBRARY__nie zostanie zdefiniowane, pojawią się błędy, czas na plan B.

gcc -dumpmachinemoże pomóc, np. dla uclibc ma -uclibcsufiks, tak jak może gcc -dumpspecs | grep dynamic-linker. Może to również oznaczać ABI.

gcc -print-file-name=libc.sopowie ci, jakiego pliku użyje kompilator dla „ -lc”, jest to prawie na pewno skrypt łączący w instalacji gcc, który możesz odczytać jako zwykły tekst. To pokaże dokładną ścieżkę do libc.so. Będzie to również działać, jeśli podajesz flagi takie jak -m32lub -m64.

W przypadku korzystania z uclibc (używanego przez OpenWRT i inne), definiuje on __UCLIBC_MAJOR__, __UCLIBC_MINOR__a __UCLIBC_SUBLEVEL__także __UCLIBC__w <features.h>, więc można go łatwo wykryć za pomocą niewielkiej odmiany powyższego fragmentu kodu C. W interesie kompatybilności uClibc może również definiować makra GNU / GLIBC, jak użyto powyżej, obecnie udaje, że jest glibc-2.2. Nie ma obecnie realizować gnu_get_libc_X()funkcje, ale nie wdrożyć getconfktóre również mogą wprowadzać w błąd (podejrzewam, że zwraca pustą odpowiedź na getconf GNU_LIBC_VERSIONmój build env jest dąsać dzisiaj więc nie mogę potwierdzić).

W mało prawdopodobnym przypadku korzystania z dietlibc , bieganie diet -vwyświetli wersję.

(FWIW, przez kilka lat z oprogramowaniem używającym autoconf miałem więcej problemów z niesprawdzonymi gcci g++wymaganymi wymaganiami niż z sprawdzonymi funkcjami glibc).

pan. spuratic
źródło
5

GNU libc (to, czego używa większość dystrybucji Linuksa w tej czy innej formie) dokłada wszelkich starań, aby zachować ścisłą kompatybilność wsteczną. Dlatego powinieneś mieć kłopoty tylko wtedy, gdy spróbujesz uruchomić zbyt nowy plik binarny na starej wersji (lub dystrybucji „korporacyjnej”, zwykle zamrażają wersje, szczególnie te fundamentalne, takie jak biblioteka C, poprawki backporting przy jednoczesnym zachowaniu ścisłej zgodności binarnej) . Uważam, że jesteś znacznie bardziej narażony na problemy z innymi bibliotekami (C ++ miał kilka zmian API / ABI w ostatniej pamięci, niektóre inne biblioteki po prostu nie dbają o kompatybilność wsteczną).

Niestety jedynym sposobem, aby się przekonać, jest spróbowanie.

vonbrand
źródło
+1 W rzeczywistości mają tabelę dotyczącą kompatybilności wstecznej i przypuszczam, że jedynym powodem, dla którego nie wszystko jest w 100%, jest kod wykorzystujący ezoteryczne rozszerzenia GNU. Jednak nie ma takiej tabeli, o której wiem, że dotyczy kompatybilności w przód , co, jak zauważasz, jest bardziej istotnym problemem.
goldilocks
5

(Jest to w zasadzie to samo, co odpowiedź złotonośnych, ale z pewnym wyjaśnieniem tego, co dzieje się pod maską.)

Podstawowa biblioteka współdzielona dla GNU libc libc.so.6(w Linuksie; Hurd ma inną SONAME), ma niezwykłą właściwość (dla bibliotek współdzielonych), którą można wywołać jako plik wykonywalny. Jeśli tak, wypisuje coś, co narzędzia GNU zwykle drukują po uruchomieniu --version, na przykład:

$ /lib/x86_64-linux-gnu/libc.so.6 
GNU C Library (Debian EGLIBC 2.18-4) stable release version 2.18, by Roland McGrath et al.
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.8.2.
Compiled on a Linux 3.12.6 system on 2014-03-02.
Available extensions:
    crypt add-on version 2.1 by Michael Glad and others
    GNU Libidn by Simon Josefsson
    Native POSIX Threads Library by Ulrich Drepper et al
    BIND-8.2.3-T5B
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<http://www.debian.org/Bugs/>.

Ale oczywiście nie ma katalogu, w którym libc.so.6nie ma życia $PATH, więc musisz wiedzieć, gdzie go szukać. To może być /lib, /lib64, /usr/lib, lub coś jeszcze wackier (jak w tym przypadku). Dogodnie lddpowie ci:

$ ldd /bin/sh | grep libc
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5660b93000)

Aby to zadziałało, oczywiście musisz znać pełną ścieżkę dynamicznie połączonego binarnego pliku wykonywalnego. Plik shwykonywalny na pewno jest w /bin(ponieważ tak wiele #!skryptów się spodziewa) i sam nie może być #!skryptem. To mogłaby być powiązana statycznie, ale ja nie spotkałem system, który zrobił na wiele lat.

Nie wiem, co robisz, jeśli biegasz z uClibc lub muslem lub czymś bardziej egzotycznym.

zwol
źródło
2
Cóż, nie musisz znać pełnej ścieżki do / bin / sh czy cokolwiek innego. Można zawsze $ ldd $(which sh) | grep libc. : D
Matt Nordhoff,
5

Innym sposobem na uzyskanie:

getconf GNU_LIBC_VERSION
Cuonglm
źródło
Fajny, powinien działać niezawodnie, ponieważ glibc-2.3.3.
mr. Spuratic