GNU/Linux >> Znalost Linux >  >> Linux

Jak mohu odkazovat na konkrétní verzi glibc?

Máte pravdu v tom, že glibc používá verzování symbolů. Pokud jste zvědaví, implementace verzování symbolů představená v glibc 2.1 je popsána zde a je rozšířením zde popsaného schématu verzování symbolů společnosti Sun.

Jednou z možností je staticky propojit váš binární soubor. Toto je pravděpodobně nejjednodušší možnost.

Můžete také vytvořit svůj binární soubor v prostředí sestavení chroot nebo pomocí glibc-nové => glibc-starý cross-compiler.

Podle http://www.trevorpounds.com blogového příspěvku Linking to Older Versioned Symbols (glibc) , je možné vynutit propojení jakéhokoli symbolu se starším, pokud je platný pomocí stejného .symver pseudo-op, který se používá především pro definování verzovaných symbolů. Následující příklad je výňatek z příspěvku na blogu.

Následující příklad využívá realpath glibc, ale zajišťuje, že je propojena se starší verzí 2.2.5.

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

__asm__(".symver realpath,[email protected]_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;
}

Nastavení 1:zkompilujte si vlastní glibc bez vyhrazeného GCC a použijte jej

Protože se zdá nemožné dělat pouze hacky týkající se verzí symbolů, pojďme o krok dále a zkompilujeme glibc sami.

Toto nastavení může fungovat a je rychlé, protože nepřekompiluje celý nástroj GCC, pouze glibc.

Není však spolehlivý, protože používá objekty hostitele C runtime, jako je crt1.o , crti.o a crtn.o poskytuje glibc. Toto je zmíněno na:https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location Tyto objekty provádějí brzké nastavení, na které se glibc spoléhá, ​​takže bych nebyl překvapen, kdyby se věci zhroutily v úžasném a úžasně jemné způsoby.

Pro spolehlivější nastavení viz Nastavení 2 níže.

Sestavte glibc a nainstalujte lokálně:

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`

Nastavení 1:ověřte sestavení

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);
}

Zkompilujte a spusťte pomocí 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

Výstupem programu je očekávané:

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

Příkaz upraven z https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location but --sysroot selhal pomocí:

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

tak jsem to odstranil.

ldd výstup potvrzuje, že ldd a knihovny, které jsme právě vytvořili, se skutečně používají podle očekávání:

+ 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)

gcc výstup ladění kompilace ukazuje, že byly použity moje hostitelské runtime objekty, což je špatné, jak bylo zmíněno dříve, ale nevím, jak to obejít, např. obsahuje:

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

Nastavení 1:úprava glibc

Nyní upravíme glibc pomocí:

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)");

Poté znovu zkompilujte a znovu nainstalujte glibc a znovu zkompilujte a znovu spusťte náš program:

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

a vidíme hacked vytištěno několikrát podle očekávání.

To dále potvrzuje, že jsme skutečně použili glibc, který jsme zkompilovali, a ne hostitelský.

Testováno na Ubuntu 18.04.

Nastavení 2:Dokonalé nastavení crosstool-NG

Toto je alternativa k nastavení 1 a je to nejsprávnější nastavení, kterého jsem dosud dosáhl:vše je v pořádku, pokud mohu pozorovat, včetně objektů C runtime, jako je crt1.o , crti.o a crtn.o .

V tomto nastavení zkompilujeme úplný vyhrazený toolchain GCC, který používá glibc, který chceme.

Jedinou nevýhodou této metody je, že sestavení bude trvat déle. Ale neriskoval bych produkční nastavení s ničím menším.

crosstool-NG je sada skriptů, která pro nás stahuje a kompiluje vše ze zdroje, včetně GCC, glibc a binutils.

Ano, sestavovací systém GCC je tak špatný, že na to potřebujeme samostatný projekt.

Toto nastavení není dokonalé, protože crosstool-NG nepodporuje vytváření spustitelných souborů bez extra -Wl flags, což je divný pocit, protože jsme vytvořili samotné GCC. Ale zdá se, že vše funguje, takže je to jen nepříjemnost.

Získejte crosstool-NG a nakonfigurujte jej:

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

Jedinou povinnou možností, kterou vidím, je zajistit, aby odpovídala verzi vašeho hostitelského jádra, aby používala správné hlavičky jádra. Najděte verzi hostitelského jádra pomocí:

uname -a

což mi ukazuje:

4.15.0-34-generic

tedy v menuconfig Já ano:

  • Operating System
    • Version of linux

takže vybírám:

4.14.71

což je první stejná nebo starší verze. Musí být starší, protože jádro je zpětně kompatibilní.

Nyní můžete stavět pomocí:

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

a nyní počkejte asi třicet minut až dvě hodiny na kompilaci.

Nastavení 2:volitelné konfigurace

.config které jsme vygenerovali pomocí ./ct-ng x86_64-unknown-linux-gnu má:

CT_GLIBC_V_2_27=y

Chcete-li to změnit, v menuconfig udělat:

  • C-library
  • Version of glibc

uložte .config a pokračujte v sestavení.

Nebo, pokud chcete použít svůj vlastní zdroj glibc, např. pro použití glibc z nejnovějšího git postupujte takto:

  • Paths and misc options
    • Try features marked as EXPERIMENTAL :nastaveno na hodnotu true
  • C-library
    • Source of glibc
      • Custom location :řekni ano
      • Custom location
        • Custom source location :přejděte na adresář obsahující váš zdroj glibc

kde glibc byl klonován jako:

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

Nastavení 2:vyzkoušejte to

Jakmile vytvoříte požadovaný nástrojový řetězec, vyzkoušejte jej pomocí:

#!/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

Zdá se, že vše funguje jako v Nastavení 1, až na to, že nyní byly použity správné runtime objekty:

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

Nastavení 2:neúspěšný pokus o efektivní rekompilaci glibc

Zdá se, že s crosstool-NG to není možné, jak je vysvětleno níže.

Pokud jste právě přestavěli;

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

pak se vezmou v úvahu vaše změny ve vlastním umístění zdroje glibc, ale vše vytváří od začátku, takže je pro iterativní vývoj nepoužitelný.

Pokud to uděláme:

./ct-ng list-steps

poskytuje pěkný přehled kroků sestavení:

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.

proto vidíme, že existují kroky glibc propojené s několika kroky GCC, zejména libc_start_files je před cc_core_pass_2 , což je pravděpodobně nejdražší krok spolu s cc_core_pass_1 .

Chcete-li sestavit pouze jeden krok, musíte nejprve nastavit "Uložit mezikroky" v .config možnost pro počáteční sestavení:

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

a pak můžete zkusit:

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

ale bohužel + vyžadováno, jak je uvedeno na:https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536

Všimněte si však, že restartování v mezikroku resetuje instalační adresář do stavu, v jakém byl během tohoto kroku. To znamená, že budete mít přestavěnou knihovnu libc – ale žádný konečný kompilátor vytvořený s touto knihovnou libc (a tudíž ani žádné knihovny kompilátorů jako libstdc++).

a v zásadě je přestavba stále příliš pomalá na to, aby byla proveditelná pro vývoj, a nevím, jak to překonat bez záplatování crosstool-NG.

Navíc počínaje libc nezdálo se, že by step znovu zkopíroval zdroj z Custom source location , což dále činí tuto metodu nepoužitelnou.

Bonus:stdlibc++

Bonus, pokud vás také zajímá standardní knihovna C++:Jak upravit a znovu sestavit zdrojový kód standardní knihovny GCC libstdc++ C++?


Linux
  1. Jak přepnout verzi PHP

  2. Jak zjistit Bash>=4.0?

  3. Jak mohu vypočítat IP adresu na konkrétních rozsazích podsítě CDIR?

  1. Jak mohu najít verzi Fedory, kterou používám?

  2. Jak mohu propojit starší verzi sdílené knihovny

  3. Jak najdu svou verzi shellu pomocí příkazu Linux?

  1. Jak zkontrolovat verzi CentOS

  2. Jak mohu odinstalovat nebo upgradovat svou starou verzi node.js?

  3. Jak mohu odstranit konkrétní pravidla z iptables?