Várias bibliotecas glibc em um único host

Várias bibliotecas glibc em um único host

Meu servidor linux (SLES-8) atualmente possui o glibc-2.2.5-235, mas eu tenho um programa que não funciona nesta versão e requer o glibc-2.3.3.

É possível ter vários glibcs ​​instalados no mesmo host?

Este é o erro que recebo quando executo meu programa no antigo glibc:

./myapp: /lib/i686/libc.so.6: version `GLIBC_2.3' not found (required by ./myapp) ./myapp: /lib/i686/libpthread.so.0: version `GLIBC_2.3.2' not found (required by ./myapp) ./myapp: /lib/i686/libc.so.6: version `GLIBC_2.3' not found (required by ./libxerces-c.so.27) ./myapp: /lib/ld-linux.so.2: version `GLIBC_2.3' not found (required by ./libstdc++.so.6) ./myapp: /lib/i686/libc.so.6: version `GLIBC_2.3' not found (required by ./libstdc++.so.6) 

Então eu criei um novo diretório chamado newglibc e copiei os seguintes arquivos em:

 libpthread.so.0 libm.so.6 libc.so.6 ld-2.3.3.so ld-linux.so.2 -> ld-2.3.3.so 

e

 export LD_LIBRARY_PATH=newglibc:$LD_LIBRARY_PATH 

Mas recebo um erro:

 ./myapp: /lib/ld-linux.so.2: version `GLIBC_PRIVATE' not found (required by ./newglibc/libpthread.so.0) ./myapp: /lib/ld-linux.so.2: version `GLIBC_2.3' not found (required by libstdc++.so.6) ./myapp: /lib/ld-linux.so.2: version `GLIBC_PRIVATE' not found (required by ./newglibc/libm.so.6) ./myapp: /lib/ld-linux.so.2: version `GLIBC_2.3' not found (required by ./newglibc/libc.so.6) ./myapp: /lib/ld-linux.so.2: version `GLIBC_PRIVATE' not found (required by ./newglibc/libc.so.6) 

Então parece que eles ainda estão ligando para / lib e não pegando de onde eu os coloquei?

obrigado

É muito possível ter várias versões do glibc no mesmo sistema (fazemos isso todos os dias).

No entanto, você precisa saber que o glibc consiste em várias partes (mais de 200 bibliotecas compartilhadas) que devem corresponder. Uma das partes é ld-linux.so.2 e deve corresponder a libc.so.6, ou você verá os erros que está vendo.

O caminho absoluto para o ld-linux.so.2 é codificado no executável no momento do link, e não pode ser facilmente alterado depois que o link é feito.

Para construir um executável que funcionará com o novo glibc, faça o seguinte:

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

A opção -rpath linker fará com que o carregador de tempo de execução procure por bibliotecas em /path/to/newglibc (para que você não tenha que configurar LD_LIBRARY_PATH antes de executá-lo), e a opção -dynamic-linker irá “assar” caminho para corrigir ld-linux.so.2 no aplicativo.

Se você não pode revincular o aplicativo myapp (por exemplo, porque é um binário de terceiros), nem tudo está perdido, mas fica mais complicado. Uma solução é definir um ambiente chroot adequado para isso. Outra possibilidade é usar o rtldi e um editor binário .

Use LD_PRELOAD: coloque sua biblioteca em algum lugar fora dos diretórios man lib e execute:

 LD_PRELOAD='mylibc.so anotherlib.so' program 

Veja: o artigo da Wikipedia

Esta questão é antiga, as outras respostas são antigas. A resposta do “Employed Russian” é muito boa e informativa, mas só funciona se você tiver o código fonte. Se você não o fizer, as alternativas naquela época seriam muito complicadas. Felizmente hoje em dia temos uma solução simples para este problema (como comentado em uma de suas respostas), usando o patch . Tudo o que tem a fazer é:

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

E depois disso, você pode simplesmente executar o seu arquivo:

 $ ./myapp 

Não há necessidade de chroot ou editar manualmente binários, felizmente. Mas lembre-se de fazer um backup do seu binário antes de aplicá-lo, se você não tiver certeza do que está fazendo, porque ele modifica seu arquivo binário. Depois de corrigi-lo, você não pode restaurar o caminho antigo para o interpretador / rpath. Se não funcionar, você terá que continuar corrigindo até encontrar o caminho que realmente funcionará … Bem, não precisa ser um processo de tentativa e erro. Por exemplo, no exemplo do OP, ele precisava do GLIBC_2.3 , para que você possa encontrar facilmente qual lib fornece essa versão usando strings :

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

Em teoria, o primeiro grep viria vazio porque o sistema libc não tem a versão que ele quer, e o segundo deve gerar o GLIBC_2.3 porque ele tem a versão que o myapp está usando, então sabemos que podemos patchelf nosso binário usando esse caminho.

Quando você tenta executar um binário no linux, o binário tenta carregar o vinculador, depois as bibliotecas, e todas elas devem estar no caminho e / ou no lugar certo. Se o seu problema é com o linker e você quer descobrir qual caminho seu binário está procurando, você pode descobrir com este comando:

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

Se o seu problema é com as libs, os comandos que lhe darão as libs sendo usadas são:

 $ readelf -d myapp | grep Shared $ ldd myapp 

Isto listará as bibliotecas que seu binário precisa, mas você provavelmente já conhece as problemáticas, já que elas já estão gerando erros como no caso do OP.

“patchelf” funciona para muitos problemas diferentes que você pode encontrar ao tentar executar um programa relacionado a esses dois problemas. Por exemplo, se você obtiver: ELF file OS ABI invalid , pode ser corrigido definindo um novo carregador (a parte --set-interpreter do comando) como explicarei aqui . Outro exemplo é o problema de não obter No such file or directory quando você executa um arquivo que está lá e é executável, como exemplificado aqui . Nesse caso em particular, o OP não tinha um link para o carregador, mas talvez no seu caso você não tenha access root e não possa criar o link. Definir um novo intérprete resolveria seu problema.

Obrigado empregado russo e Michael Pankov para a visão e solução!

Você pode considerar o uso do Nix http://nixos.org/nix/ ?

O Nix suporta o gerenciamento de pacotes multiusuário: vários usuários podem compartilhar um armazenamento Nix comum com segurança, não precisam ter privilégios de administrador para instalar o software e podem instalar e usar diferentes versões de um pacote.

Em primeiro lugar, a dependência mais importante de cada programa vinculado dinamicamente é o vinculador. Todas as bibliotecas precisam corresponder à versão do vinculador.

Vamos dar um exemplo simples: eu tenho o sistema Ubuntu newset onde eu corro algum programa (no meu caso é o compilador D – ldc2). Eu gostaria de executá-lo no antigo CentOS, mas por causa da biblioteca glibc mais antiga é impossível. Eu tenho

 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) 

Eu tenho que copiar todas as dependencies do Ubuntu para o centos. O método adequado é o seguinte:

Primeiro, vamos verificar todas as dependencies:

 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) 

O linux-vdso.so.1 não é uma biblioteca real e não precisamos nos preocupar com isso.

/lib64/ld-linux-x86-64.so.2 é o linker, que é usado pelo linux para vincular o executável a todas as bibliotecas dinâmicas.

Restos dos arquivos são bibliotecas reais e todos eles junto com o linker devem ser copiados em algum lugar no centos.

Vamos supor que todas as bibliotecas e vinculadores estejam no diretório “/ mylibs”.

ld-linux-x86-64.so.2 – como eu já disse – é o linker. Não é uma biblioteca dinâmica, mas um executável estático. Você pode executá-lo e ver que ele ainda tem alguns parâmetros, por exemplo – caminho da biblioteca (eu retornarei a ele).

No linux, o programa dinamicamente vinculado pode ser chamado apenas pelo nome, por exemplo

 /bin/ldc2 

O Linux carrega esse programa na RAM e verifica qual linker está configurado para ele. Normalmente, no sistema de 64 bits, é /lib64/ld-linux-x86-64.so.2 (em seu sistema de arquivos é um link simbólico para o executável real). Então o linux executa o linker e carrega bibliotecas dinâmicas.

Você também pode mudar isso um pouco e fazer esse truque:

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

É o método para forçar o linux a usar o linker específico.

E agora podemos retornar ao parâmetro anterior mencionado – caminho da biblioteca

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

Ele executará o ldc2 e carregará bibliotecas dinâmicas de / mylibs.

Este é o método para chamar o executável com bibliotecas escolhidas (não padrão do sistema).

Se você observar atentamente a segunda saída, poderá ver que o novo local das bibliotecas é usado. Talvez ainda estejam faltando bibliotecas que fazem parte do glibc.

Eu também acho que todas as bibliotecas usadas pelo seu programa devem ser compiladas contra essa versão do glibc. Se você tiver access ao código-fonte do programa, uma nova compilation parece ser a melhor solução.

“Employed Russian” está entre as melhores respostas, e acho que todas as outras respostas sugeridas podem não funcionar. O motivo é simplesmente porque, quando um aplicativo é criado pela primeira vez, todas as APIs de que ele precisa são resolvidas em tempo de compilation. Usando “ldd” você pode ver todas as dependencies vinculadas estaticamente:

 ldd /usr/lib/firefox/firefox linux-vdso.so.1 => (0x00007ffd5c5f0000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f727e708000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f727e500000) libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f727e1f8000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f727def0000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f727db28000) /lib64/ld-linux-x86-64.so.2 (0x00007f727eb78000) libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f727d910000) 

Mas, em tempo de execução, o firefox também carregará muitas outras bibliotecas dinâmicas, por exemplo (para o firefox) existem muitas bibliotecas rotuladas “glib” carregadas (mesmo que estaticamente vinculadas não existam):

  /usr/lib/x86_64-linux-gnu/libdbus-glib-1.so.2.2.2 /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0 /usr/lib/x86_64-linux-gnu/libavahi-glib.so.1.0.2 

Muitas vezes, você pode ver os nomes de uma versão sendo ligada a outra versão. Por exemplo:

 lrwxrwxrwx 1 root root 23 Dec 21 2014 libdbus-glib-1.so.2 -> libdbus-glib-1.so.2.2.2 -rw-r--r-- 1 root root 160832 Mar 1 2013 libdbus-glib-1.so.2.2.2 

Isto significa, portanto, que existe uma versão diferente de “bibliotecas” em um sistema – o que não é um problema, pois é o mesmo arquivo, e fornecerá compatibilidades quando os aplicativos tiverem dependencies de várias versões.

Portanto, no nível do sistema, todas as bibliotecas são quase interdependentes uma da outra, e apenas alterar a prioridade de carregamento das bibliotecas através da manipulação de LD_PRELOAD ou LD_LIBRARY_PATH não ajudará – mesmo que possa carregar, o tempo de execução pode falhar.

http://lightofdawn.org/wiki/wiki.cgi/-wiki/NewAppsOnOldGlibc

A melhor alternativa é o chroot (mencionado por ER brevemente): mas para isso você precisará recriar todo o ambiente no qual o binário original é executado – geralmente a partir de / lib, / usr / lib /, / usr / lib / x86 etc. Você pode usar “Buildroot”, ou YoctoProject, ou apenas tar de um ambiente existente do Distro. (como o Fedora / Suse etc).

Não tenho certeza se a pergunta ainda é relevante, mas existe outra maneira de corrigir o problema: o Docker. É possível instalar um contêiner quase vazio da Distribuição de origem (a distribuição usada para desenvolvimento) e copiar os arquivos no contêiner. Dessa forma, você não precisa criar o sistema de arquivos necessário para o chroot.

Quando eu quis rodar um navegador chromium no Ubuntu preciso (glibc-2.15), recebi a mensagem (típica) “… libc.so.6: version` GLIBC_2.19 ‘not found … “. Eu considerei o fato de que os arquivos não são necessários permanentemente, mas apenas para iniciar. Então eu peguei os arquivos necessários para o navegador e o sudo e criei um ambiente mini-glibc-2.19-, iniciei o navegador e depois copiei os arquivos originais de volta. Os arquivos necessários estão na RAM e o glibc original é o mesmo.

 as root the files (*-2.15.so) already exist 

mkdir -p /glibc-2.19/i386-linux-gnu

 /glibc-2.19/ld-linux.so.2 -> /glibc-2.19/i386-linux-gnu/ld-2.19.so /glibc-2.19/i386-linux-gnu/libc.so.6 -> libc-2.19.so /glibc-2.19/i386-linux-gnu/libdl.so.2 -> libdl-2.19.so /glibc-2.19/i386-linux-gnu/libpthread.so.0 -> libpthread-2.19.so 

mkdir -p /glibc-2.15/i386-linux-gnu

 /glibc-2.15/ld-linux.so.2 -> (/glibc-2.15/i386-linux-gnu/ld-2.15.so) /glibc-2.15/i386-linux-gnu/libc.so.6 -> (libc-2.15.so) /glibc-2.15/i386-linux-gnu/libdl.so.2 -> (libdl-2.15.so) /glibc-2.15/i386-linux-gnu/libpthread.so.0 -> (libpthread-2.15.so) 

o script para executar o navegador:

 #!/bin/sh sudo cp -r /glibc-2.19/* /lib /path/to/the/browser & sleep 1 sudo cp -r /glibc-2.15/* /lib sudo rm -r /lib/i386-linux-gnu/*-2.19.so