Pesquisar neste blog

segunda-feira, 23 de abril de 2012

Aprenda Linux, 101: Gerenciar bibliotecas compartilhadas

Resumo:  Aprenda a determinar quais são as bibliotecas compartilhadas necessárias aos seus programas executáveis do Linux® e como carregá-las. Use o material deste artigo para se preparar para o exame LPI 101 de certificação de administrador de sistema Linux ou simplesmente por diversão.





Neste artigo, você aprenderá a localizar e carregar as bibliotecas compartilhadas necessárias aos seus programas do Linux. Aprenda a:
  • Determinar quais bibliotecas um programa necessita
  • Saber como o sistema localiza bibliotecas compartilhadas
  • Carregar bibliotecas compartilhadas
Este artigo lhe ajuda na preparação para o objetivo 102.3 do tópico 102 do exame Junior Level Administration (LPIC-1) 101 do Linux Professional Institute. O objetivo tem peso 1.
Para tirar o máximo dos artigos desta série, é necessário ter conhecimento básico de Linux e possuir um sistema Linux funcional em que seja possível praticar os comandos aqui abordados. Algumas vezes, é possível que versões diferentes de determinado programa formatem a saída de modo diferente, assim, pode ser que seus resultados não sejam exatamente iguais às listas e figuras exibidas neste documento. Particularmente, muitos dos exemplos deste artigo vêm de sistemas de 64 bits. Nós incluímos alguns exemplos de sistemas de 32 bits para ilustrar diferenças importantes.


Entre em contato com Ian

Ian é um dos nossos autores mais populares e produtivos. Pesquise todos os artigos do Ian no developerWorks. Confira o perfil de Ian e entre em contato com ele, com outros autores e leitores no My developerWorks.
Os sistemas Linux têm dois tipos de programas executáveis:
  • Executáveis vinculados estaticamente contêm todas as funções da biblioteca que eles têm de executar; todas as funções da biblioteca estão vinculadas no executável. Eles são programas completos que não dependem de bibliotecas externas para execução. Uma vantagem de programas vinculados estaticamente é que eles funcionam sem pré-requisitos de instalação.
  • Os executáveis vinculados dinamicamente são programas muito menores e incompletos, ou seja, eles precisam de funções de bibliotecas compartilhadas externas para serem executados. Além de ser menor, o link dinâmico permite que um pacote especifique bibliotecas de pré-requisito sem a necessidade de incluí-las no pacote. O uso de link dinâmico também permite que muitos programas em execução compartilhem uma cópia de uma biblioteca em vez de ocupar a memória com muitas cópias do mesmo código. Por esses motivos, a maioria dos programas atualmente usa link dinâmico.
Um exemplo interessante em muitos sistemas Linux é o comando ln (/bin/ln), que cria links entre arquivos, sejam eles linksfísicos ou não-físicos (ou simbólicos). Este comando usa bibliotecas compartilhadas. Bibliotecas compartilhadas frequentemente envolvem links simbólicos entre um nome genérico para a biblioteca e um nível específico da biblioteca, assim, se os links não estão presentes ou estão quebrados por algum motivo, o próprio comando In pode estar inoperante, criando um problema circular. Para proteger-se contra essa possibilidade, alguns sistemas Linux incluem uma versão vinculada estaticamente do programa In como o programa sln (/sbin/sln). A Listagem 1 ilustra as grandes diferenças de tamanho entre o In dinamicamente vinculado e o sln estaticamente vinculado. O exemplo é do sistema Fedora 12 de 64 bits.

Listagem 1. Tamanhos de sln e In
[ian@echidna ~]$ ls -l /sbin/sln /bin/ln
-rwxr-xr-x. 1 root root  47384 2010-01-12 09:35 /bin/ln
-rwxr-xr-x. 1 root root 603680 2010-01-04 09:07 /sbin/sln

Embora não seja parte dos requerimentos atuais do exame LPI para este tópico, você deve saber que, hoje em dia, muitos sistemas Linux são executados em hardware que suporta executáveis tanto 32, quanto de 64 bits. Assim, muitas bibliotecas são compiladas em versões 32 e de 64 bits. As versões de 64 bits são normalmente guardadas sob a árvore /lib64 no sistema de arquivos, enquanto as versões de 32 bits ficam normalmente na árvore tradicional /lib. Você provavelmente irá achar tanto /lib/libc-2.11.1.so quanto /lib64/libc-2.11.1.so em um típico sistema Linux de 64 bits. Estas duas bibliotecas permitem que programas C 32 e de 64 bits sejam executados em um sistema Linux de 64 bits.
Apesar de sabermos que um programa vinculado estaticamente provavelmente é grande, como dizemos se um programa é vinculado estaticamente? E se for vinculado dinamicamente, como sabemos de quais bibliotecas ele precisa? O comando Iddpode responder ambas as questões. Se você está executando um sistema como Debian ou Ubuntu, provavelmente não tem o executável sln, assim, recomenda-se verificar também o executável /sbin/ldconfig. A Listagem 2 mostra a saída do comandoldd para os executáveis ln e sln, assim como para o executável ldconfig. O exemplo é do sistema Fedora 12 de 64 bits (echidna). Para comparação, a saída de um antigo sistema Fedora 8 de 32 bits (pinguino) é exibida para /bin/ln.

Listagem 2. Saída de ldd para sln e ln.
[ian@echidna ~]$ #Fedora 12 64-bit
[ian@echidna ~]$ ldd /sbin/sln /sbin/ldconfig /bin/ln
/sbin/sln:
        not a dynamic executable
/sbin/ldconfig:
        not a dynamic executable
/bin/ln:
        linux-vdso.so.1 =>  (0x00007fff644af000)
        libc.so.6 => /lib64/libc.so.6 (0x00000037eb800000)
        /lib64/ld-linux-x86-64.so.2 (0x00000037eb400000)

[ian@pinguino ~]$ # Fedora 8 32-bit
[ian@pinguino ~]$ ldd /bin/ln
        linux-gate.so.1 =>  (0x00110000)
        libc.so.6 => /lib/libc.so.6 (0x00a57000)
        /lib/ld-linux.so.2 (0x00a38000)

Devido ao fato de Idd dizer respeito a vínculos dinâmicos, ele nos informa que sln e ldconfig estão estaticamente vinculados dizendo que eles "não são executáveis dinâmicos", ao mesmo tempo em que nos informa o nome de três bibliotecas compartilhadas (linux-vdso.so.1, libc.so.6 e /lib64/ld-linux-x86-64.so.2) que o comando ln necessita. Observe que .so indica que eles são objetos compartilhados ou bibliotecas dinâmicas. Esta saída também ilustra três tipos diferentes de informações que você provavelmente verá.
linux-vdso.so.1
é o Objeto Compartilhado Dinâmico Virtual do Linux, que vamos discutir em breve. Você também poderá ver linux-gate.so.1, como no exemplo do Fedora 8.
libc.so.6
contém um ponteiro para /lib64/libc.so.6.
/lib64/ld-linux-x86-64.so.2
é o caminho absoluto para outra biblioteca.
Na Listagem 3, usamos o comando ls -l para mostrar que as últimas duas bibliotecas são, uma após a outra, links simbólicos para versões específicas das bibliotecas. O exemplo é do sistema Fedora 12 de 64 bits.

Listagem 3. Links simbólicos da biblioteca
[ian@echidna ~]$ ls -l /lib64/libc.so.6 /lib64/ld-linux-x86-64.so.2
lrwxrwxrwx. 1 root root 12 2010-01-14 14:24 /lib64/ld-linux-x86-64.so.2 -> ld-2.11.1.so
lrwxrwxrwx. 1 root root 14 2010-01-14 14:24 /lib64/libc.so.6 -> libc-2.11.1.so

Antigamente, no começo dos processadores x86, as comunicações dos programas do usuário para os serviços do supervisor eram realizadas através da interrupção de um software. Conforme a velocidade dos processadores foi aumentando, isso resultou em um gargalo muito sério. Começando com os processadores Pentium® II, a Intel® introduziu uma instalação Fast System Call para aumentar a velocidade das chamadas do sistema usando instruções SYSENTER e SYSEXIT em vez de interrupções.
A biblioteca que você vê como linux-vdso.so.1 é uma biblioteca virtual ou um Objeto Compartilhado Dinâmico Virtual, que reside somente no espaço de endereço de cada programa. Sistemas antigos chamavam isto de linux-gate.so.1. Esta biblioteca virtual fornece a lógica necessária para permitir que os programas do usuário acessem funções do sistema através dos meios mais rápidos disponíveis no processador em particular, interrompendo ou, nos processadores mais modernos, com o Fast System Call.
A partir do precedente, você pode se surpreender ao aprender que /lib/ld-linux.so.2 e seu primo de 64 bits, /lib64/ld-linux-x86-64.so.2, se parecem com bibliotecas compartilhadas, mas que são, de fato, executáveis por si mesmo. Eles são o código responsável pelo carregamento dinâmico. Eles leem as informações do cabeçalho do executável, que está no formatoExecutable and Linking Format (ELF). Com base nessas informações, eles determinam quais bibliotecas são necessárias e quais precisam ser carregadas. Em seguida, eles executam vínculos dinâmicos para corrigir todos os ponteiros de endereço do executável e das bibliotecas carregadas, para que o programa seja executado.
A man page para o ld-linux.so também descreve o ld.so, que executa funções similares para o formato binário anterior a.out. A Listagem 4 mostra o uso da opção --list dos primos do ld-linux.so para exibir as mesmas informações do comando ln que mostramos com o comando ldd na Listagem 2.

Listagem 4. Usando ld-linux.so para exibir os requerimentos da biblioteca
[ian@echidna ~]$ /lib64/ld-linux-x86-64.so.2 --list /bin/ln
        linux-vdso.so.1 =>  (0x00007fffc9fff000)
        libc.so.6 => /lib64/libc.so.6 (0x00000037eb800000)
        /lib64/ld-linux-x86-64.so.2 (0x00000037eb400000)

[ian@pinguino ~]$ /lib/ld-linux.so.2 --list /bin/ln
        linux-gate.so.1 =>  (0x00110000)
        libc.so.6 => /lib/libc.so.6 (0x00a57000)
        /lib/ld-linux.so.2 (0x00a38000)

Observe que os endereços hexa podem ser diferentes entre as duas listagens. Eles também serão provavelmente diferentes se ldd for executado duas vezes.
Então, como o loader dinâmico sabe onde procurar os executáveis? Assim como muitas coisas no Linux, há um arquivo de configuração em /etc. De fato, há dois arquivos de configuração, /etc/ld/so/conf e /etc/ld.so.cache. A Listagem 5 mostra o conteúdo de /etc/ld.so.conf em um sistema Fedora 12 de 64 bits. Observe que /etc/ld.so.conf especifica que todos os arquivos .conf do subdiretório ld.so.conf.d devem ser incluídos. Sistemas mais antigos podem conter todas as entradas em /etc/ld/so/conf e não incluir entradas do diretório /etc/ld.so.conf.d. O conteúdo real de /etc/ld.so.conf ou do diretório /etc/ld.so.conf.d pode ser diferente no seu sistema.

Listagem 5. Conteúdo de /etc/ld.so.conf.
[ian@echidna ~]$ cat /etc/ld.so.conf
include ld.so.conf.d/*.conf
[ian@echidna ~]$ ls /etc/ld.so.conf.d/*.conf
/etc/ld.so.conf.d/kernel-2.6.31.12-174.2.19.fc12.x86_64.conf
/etc/ld.so.conf.d/kernel-2.6.31.12-174.2.22.fc12.x86_64.conf
/etc/ld.so.conf.d/kernel-2.6.31.12-174.2.3.fc12.x86_64.conf
/etc/ld.so.conf.d/mysql-x86_64.conf
/etc/ld.so.conf.d/qt-x86_64.conf
/etc/ld.so.conf.d/tix-x86_64.conf
/etc/ld.so.conf.d/xulrunner-64.conf

O carregamento dos programas deve ser rápido, assim, use o comando ldconfig para processar o arquivo ld.so.conf e todos os arquivos incluídos do ld.so.conf, assim como bibliotecas dos diretórios confiáveis, /lib e /usr/lib, e quaisquer outras na linha de comando. O comando ldconfig cria os links e o cache necessários para bibliotecas compartilhadas recentemente usadas em /etc/ld.so.cache. O loader dinâmico usa a informação em cache para localizar arquivos que devem ser carregados e vinculados dinamicamente. Se você alterar ld.so.conf (ou adicionar novos arquivos incluídos a ld.so.conf.d), será preciso executar o comando ldconfig (como root) para criar novamente o arquivo ld.so.cache.
Normalmente, você usa o comando ldconfig sem parâmetros para criar novamente ld.so.cache. Há vários outros parâmetros que podem ser especificados para substituir esse comportamento padrão. Como de costume, tente man ldconfig para mais informações. A Listagem 6 mostra o uso do parâmetro -p para exibir os conteúdos de ld.so.cache.

Listagem 6. Usando ldconfig para exibir ld.so.cache
[ian@lyrebird ian]$ /sbin/ldconfig -p | less
1602 libs found in cache `/etc/ld.so.cache'
        libzip.so.1 (libc6,x86-64) => /usr/lib64/libzip.so.1
        libz.so.1 (libc6,x86-64) => /lib64/libz.so.1
        libz.so (libc6,x86-64) => /usr/lib64/libz.so
        libx86.so.1 (libc6,x86-64) => /usr/lib64/libx86.so.1
        libx11globalcomm.so.1 (libc6,x86-64) => /usr/lib64/libx11globalcomm.so.1
        libxul.so (libc6,x86-64) => /usr/lib64/xulrunner-1.9.1/libxul.so
        libxtables.so.2 (libc6,x86-64) => /usr/lib64/libxtables.so.2
        libxslt.so.1 (libc6,x86-64) => /usr/lib64/libxslt.so.1
        libxslt.so (libc6,x86-64) => /usr/lib64/libxslt.so
        libxpcom.so (libc6,x86-64) => /usr/lib64/xulrunner-1.9.1/libxpcom.so
        libxml2.so.2 (libc6,x86-64) => /usr/lib64/libxml2.so.2
        libxml2.so (libc6,x86-64) => /usr/lib64/libxml2.so
       ...
        libABRTdUtils.so.0 (libc6,x86-64) => /usr/lib64/libABRTdUtils.so.0
        libABRTUtils.so.0 (libc6,x86-64) => /usr/lib64/libABRTUtils.so.0
        ld-linux.so.2 (ELF) => /lib/ld-linux.so.2
        ld-linux-x86-64.so.2 (libc6,x86-64) => /lib64/ld-linux-x86-64.so.2

Caso você esteja executando um aplicativo mais antigo, que necessite de uma versão específica mais antiga de uma biblioteca compartilhada, ou se você está desenvolvendo uma nova biblioteca compartilhada ou versão de uma biblioteca compartilhada, é recomendado substituir os caminhos padrões de procura usados pelo loader. Isso pode também ser solicitado pelos scripts que usam bibliotecas compartilhadas específicas de produto, que podem estar instaladas na árvore /opt.
Do mesmo modo que é possível definir a variável PATH para especificar um caminho de procura para executáveis, é possível definir a variável LD_LIBRARY_PATH para uma lista de diretórios separados por sinais de dois pontos, onde se deve procurar por bibliotecas compartilhadas antes das bibliotecas do sistema especificadas em ld.so.cache. Por exemplo, você pode usar um comando como:
export LD_LIBRARY_PATH=/usr/lib/oldstuff:/opt/IBM/AgentController/lib


Nenhum comentário: