GNU/Linux >> Znalost Linux >  >> Linux

Více knihoven glibc na jednom hostiteli

Tato otázka je stará, ostatní odpovědi jsou staré. Odpověď "Employed Russian" je velmi dobrá a informativní, ale funguje pouze v případě, že máte zdrojový kód. Pokud ne, tehdejší alternativy byly velmi složité. Naštěstí dnes máme jednoduché řešení tohoto problému (jak komentoval v jedné z jeho odpovědí), pomocí patchelfu. Vše, co musíte udělat, je:

$ ./patchelf --set-interpreter /path/to/newglibc/ld-linux.so.2 --set-rpath /path/to/newglibc/ myapp

A poté můžete svůj soubor spustit:

$ ./myapp

Není třeba chroot nebo ručně upravit binární soubory, naštěstí. Pokud si však nejste jisti, co děláte, nezapomeňte si před opravou binární soubor zálohovat, protože to upravuje váš binární soubor. Po záplatě nemůžete obnovit starou cestu na interpret/rpath. Pokud to nepůjde, budete to muset opravovat, dokud nenajdete cestu, která bude skutečně fungovat... No, nemusí to být proces pokus-omyl. Například v příkladu OP potřeboval GLIBC_2.3 , takže pomocí strings snadno zjistíte, která knihovna tuto verzi poskytuje :

$ strings /lib/i686/libc.so.6 | grep GLIBC_2.3
$ strings /path/to/newglib/libc.so.6 | grep GLIBC_2.3

Teoreticky by první grep byl prázdný, protože systémová knihovna libc nemá verzi, kterou chce, a druhý by měl vydávat GLIBC_2.3, protože má verzi myapp používá, takže víme, že můžeme patchelf naše binární pomocí této cesty. Pokud dojde k chybě segmentace, přečtěte si poznámku na konci.

Když se pokusíte spustit binární soubor v linuxu, binární soubor se pokusí načíst linker, pak knihovny a všechny by měly být v cestě a/nebo na správném místě. Pokud je váš problém s linkerem a chcete zjistit, jakou cestu váš binární soubor hledá, můžete to zjistit pomocí tohoto příkazu:

$ readelf -l myapp | grep interpreter
  [Requesting program interpreter: /lib/ld-linux.so.2]                                                                                                                                                                                   

Pokud je váš problém s libs, příkazy, které vám poskytnou používané libs, jsou:

$ readelf -d myapp | grep Shared
$ ldd myapp 

Toto zobrazí seznam knihoven, které vaše binární soubory potřebují, ale pravděpodobně již znáte ty problematické, protože již poskytují chyby jako v případě OP.

"patchelf" funguje pro mnoho různých problémů, se kterými se můžete setkat při pokusu o spuštění programu, související s těmito 2 problémy. Pokud například získáte:ELF file OS ABI invalid , lze to opravit nastavením nového zavaděče (--set-interpreter část příkazu), jak zde vysvětluji. Dalším příkladem je problém získat No such file or directory když spustíte soubor, který tam je a je spustitelný, jak je ukázáno zde. V tomto konkrétním případě OP postrádal odkaz na zavaděč, ale možná ve vašem případě nemáte přístup root a nemůžete odkaz vytvořit. Nastavení nového tlumočníka by váš problém vyřešilo.

Děkujeme Employed Russian a Michael Pankov za pochopení a řešení!

Poznámka pro chybu segmentace:můžete být v případě myapp používá několik knihoven a většina z nich je v pořádku, ale některé ne; pak vy patchelf do nového adresáře a dostanete chybu segmentace. Když patchelf vašeho binárního souboru, změníte cestu několika knihoven, i když některé byly původně v jiné cestě. Podívejte se na můj příklad níže:

$ ldd myapp
./myapp: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by ./myapp)
./myapp: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by ./myapp)
        linux-vdso.so.1 =>  (0x00007fffb167c000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9a9aad2000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f9a9a8ce000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f9a9a6af000)
        libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f9a9a3ab000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9a99fe6000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f9a9adeb000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f9a99dcf000)

Všimněte si, že většina knihoven je v /lib/x86_64-linux-gnu/ ale ten problematický (libstdc++.so.6 ) je na /usr/lib/x86_64-linux-gnu . Poté, co jsem opravil myapp přejděte na /path/to/mylibs , mám chybu segmentace. Z nějakého důvodu nejsou knihovny zcela kompatibilní s binárním souborem. Od myapp nestěžoval jsem si na původní libs, zkopíroval jsem je z /lib/x86_64-linux-gnu/ na /path/to/mylibs2 a také jsem zkopíroval libstdc++.so.6 z /path/to/mylibs tam. Pak jsem to opravil na /path/to/mylibs2 a myapp nyní funguje. Pokud váš binární soubor používá různé knihovny a máte různé verze, může se stát, že svou situaci nebudete moci opravit. :( Ale pokud je to možné, mixování knih může být cesta. Není to ideální, ale možná bude to fungovat. Hodně štěstí!


Použijte LD_PRELOAD:umístěte svou knihovnu někam mimo adresáře man lib a spusťte:

LD_PRELOAD='mylibc.so anotherlib.so' program

Viz:článek na Wikipedii


Za prvé, nejdůležitější závislost každého dynamicky propojeného programu je linker. Všechny tyto knihovny musí odpovídat verzi linkeru.

Vezměme si jednoduchý příklad:Mám nový systém ubuntu, kde spouštím nějaký program (v mém případě je to D kompilátor - ldc2). Chtěl bych to spustit na starém CentOS, ale kvůli starší knihovně glibc to není možné. Mám

ldc2-1.5.0-linux-x86_64/bin/ldc2: /lib64/libc.so.6: version `GLIBC_2.15' not found (required by ldc2-1.5.0-linux-x86_64/bin/ldc2)
ldc2-1.5.0-linux-x86_64/bin/ldc2: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ldc2-1.5.0-linux-x86_64/bin/ldc2)

Musím zkopírovat všechny závislosti z ubuntu do centos. Správná metoda je následující:

Nejprve zkontrolujme všechny závislosti:

ldd ldc2-1.5.0-linux-x86_64/bin/ldc2 
    linux-vdso.so.1 =>  (0x00007ffebad3f000)
    librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f965f597000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f965f378000)
    libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f965f15b000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f965ef57000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f965ec01000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f965e9ea000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f965e60a000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f965f79f000)

linux-vdso.so.1 není skutečná knihovna a nemusíme se o ni starat.

/lib64/ld-linux-x86-64.so.2 je linker, který používá linux k propojení spustitelného souboru se všemi dynamickými knihovnami.

Zbytek souborů jsou skutečné knihovny a všechny spolu s linkerem musí být zkopírovány někam do centosu.

Předpokládejme, že všechny knihovny a linker jsou v adresáři "/mylibs".

ld-linux-x86-64.so.2 - jak jsem již řekl - je linker. Není to dynamická knihovna, ale statický spustitelný soubor. Můžete ji spustit a uvidíte, že má dokonce nějaké parametry, např. --library-path (k tomu se ještě vrátím).

Na linuxu může být dynamicky linkovaný program načten jen podle jeho názvu, např.

/bin/ldc2

Linux takový program nahraje do RAM a zkontroluje, který linker je pro něj nastaven. Obvykle na 64bitovém systému je to /lib64/ld-linux-x86-64.so.2 (ve vašem souborovém systému je to symbolický odkaz na skutečný spustitelný soubor). Pak linux spustí linker a načte dynamické knihovny.

Můžete to také trochu změnit a udělat takový trik:

/mylibs/ld-linux-x86-64.so.2 /bin/ldc2

Je to metoda, jak donutit linux používat konkrétní linker.

A nyní se můžeme vrátit ke zmíněnému dřívějšímu parametru --library-path

/mylibs/ld-linux-x86-64.so.2 --library-path /mylibs /bin/ldc2

Spustí ldc2 a načte dynamické knihovny z /mylibs.

Toto je metoda pro volání spustitelného souboru s vybranými (nikoli výchozími systémovými) knihovnami.


Je velmi možné mít více verzí glibc na stejném systému (děláme to každý den).

Musíte však vědět, že glibc se skládá z mnoha částí (200+ sdílených knihoven), které se všechny musí shodovat. Jedním z kusů je ld-linux.so.2 a musí odpovídat libc.so.6, nebo uvidíte chyby, které vidíte.

Absolutní cesta k ld-linux.so.2 je napevno zakódována do spustitelného souboru v čase odkazu a po vytvoření odkazu ji nelze snadno změnit (Aktualizace:lze provést pomocí patchelfu; viz tato odpověď níže).

Chcete-li sestavit spustitelný soubor, který bude fungovat s novým glibc, postupujte takto:

g++ main.o -o myapp ... \
   -Wl,--rpath=/path/to/newglibc \
   -Wl,--dynamic-linker=/path/to/newglibc/ld-linux.so.2

-rpath linker způsobí, že runtime loader vyhledá knihovny v /path/to/newglibc (takže byste nemuseli nastavovat LD_LIBRARY_PATH před spuštěním) a -dynamic-linker volba "upeče" cestu k opravě ld-linux.so.2 do aplikace.

Pokud nemůžete znovu propojit myapp aplikace (např. protože se jedná o binární soubor třetí strany), není vše ztraceno, ale bude to složitější. Jedním z řešení je nastavit správný chroot prostředí pro to. Další možností je použít rtldi a binární editor. Aktualizace:nebo můžete použít patchelf.


Linux
  1. Ssh – více podobných položek v konfiguraci Ssh?

  2. Jak hostovat více domén?

  3. Nastavte více webů WordPress na jednom VPS

  1. Jak rozdělit jeden soubor do více souborů na základě řádků

  2. Obsluhujte více domén pomocí virtuálních hostitelů

  3. scp jeden soubor na více míst

  1. Jak přejmenovat více souborů v jediném příkazu nebo skriptu v systému Unix?

  2. Ssh – Běžná vícenásobná připojení Ssh Problém se zpracováním souborů?

  3. Linux – Může mít jeden uživatel více souborů Crontab?