Preciso de uma Glibc mais recente do que o meu sistema fornece um binário que quero executar. Então, eu tenho um diretório /my_libs
com a maioria dos arquivos lib de um Ubuntu recente, incluindo o novo Glibc ( libc.so.6
).
Agora eu exportei LD_LIBRARY_PATH=/my_libs:$LD_LIBRARY_PATH
e tentei executar o meu executável. Isso falhará com SEGFAULT. De fato, todo binário falhará agora com SEGFAULT (mesmo coisas simples como /bin/ls
). Então eu acho que há alguma confusão entre diferentes bibliotecas /my_libs
e o meu sistema principal. Eu traçado com LD_DEBUG=libs
(ou LD_DEBUG=all
) e resolvi tudo, exceto de ld-linux-x86-64.so.2
. Não importa o que eu fiz até agora, ele sempre usou /lib64/ld-linux-x86-64.so.2
e não /my_libs/ld-linux-x86-64.so.2
.
Existe uma maneira de definir o caminho ld-linux
? Pelo que entendi, essa biblioteca, que também é um executável, é sempre usada para executar qualquer programa, e meu ambiente usa /lib64/ld-linux-x86-64.so.2
.
Se eu executar diretamente /my_libs/ld-linux-x86-64.so.2 /bin/ls
, funcionará. Também posso executar meu novo binário dessa maneira - só preciso ter certeza de que todas as bibliotecas são fornecidas /my_libs
ou de que as bibliotecas do sistema são compatíveis.
Então, o que posso fazer /bin/ls
usando apenas a chamada direta /my_libs/ld-linux-x86-64.so.2
?
Algumas discussões relacionadas estão aqui .
Observe que não quero corrigir /bin/ls
ou outros binários para fazer esse trabalho.
Respostas:
Tl: dr : Se você precisar continuar usando várias versões da libc , como muitos de nós, um utilitário importante a ser usado é o PatchElf .
Normalmente, se tudo o que você deseja é forçar sua própria versão do interpretador de programa ao criar seu próprio programa, tudo o que você precisa fazer é compilar com as seguintes opções:
Mas isso não funciona com utilitários de terceiros e com alguns objetos compartilhados que são no entanto executável por si mesmos, para que invocar patchelf em um determinado programa ELF como segue:
A razão pela qual não se trata apenas de editar com um editor hexadecimal o antigo executável e substituir o endereço antigo do intérprete pelo novo, é que os dois não precisam ter o mesmo tamanho; patchelf cuida de ampliar seu executável para você.
Você também pode alterar a variável rpath , da seguinte maneira:
Acho isso muito mais prático do que usar os invólucros comuns em torno de comandos com LD_LIBRARY_PATH .
Quanto ao execve , deve ser apenas a chamada de sistema mais fundamental no Unix: execve (filename) executa o nome do arquivo especificado. Por exemplo, seu shell executa um comando por meio de uma chamada da família execve : primeiro se bifurca e, em seguida, o processo filho gera o comando execve ( ls, cd ,, ... o nome dele). A maioria dos programas precisa de bibliotecas vinculadas dinamicamente, por exemplo, para ls :
Quando você carrega ls , é não o ponto de entrada normal de binário que é usado no início, mas ld-linux em vez disso: ele cuida de carregar todos os não resolvidos, as bibliotecas necessárias, e então transfere o controle para a aplicação real, ls neste caso. Faz isso executando o arquivo do programa.
Não sou capaz de dizer por que exatamente seu programa trava., Mas tentaria verificar se todos os programas invocados exigem o mesmo intérprete; você faz isso verificando a saída de:
(a ênfase é minha ...).
EDIT : uma excelente discussão de um dos autores da chamada do sistema execveat pode ser encontrada aqui , e o código do kernel relevante está aqui . O código mostra que nenhuma variável do sistema é lida e a rotina load_elf_binary examina o interpretador de programa PT_INTERP .
fonte
/bin/ls
) e não acho que seja uma boa ideia corrigir os binários do sistema para fazer isso funcionar. Não é possível substituir o interpretador de programa solicitado por algum env var? Onde está o código relacionado no kernel do Linux, onde ele lê o interpretador de programa solicitado e o executa?load_elf_binary
, e depois a verificaçãop_type == PT_INTERP
? Sim, pelo código que vejo, ele usará apenas o que está escrito no arquivo e não examinará nenhum env var. Você deve apontar isso na sua resposta. Para mim, isso significa que minha solução é realmente usar sempre o carregador ld-linux explicitamente (sem correção).