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.