Bibliotecas compartilhadas (ou objetos compartilhados) são arquivos que contêm código que pode ser usado por múltiplos programas ao mesmo tempo. No Linux, essas bibliotecas geralmente têm a extensão .so (shared object). Elas são carregadas na memória apenas uma vez, e diferentes programas podem acessar esse código compartilhado para executar funções comuns, como manipulação de arquivos ou interface gráfica.
comandos e arquivos relacionados à configuração e gestão de bibliotecas em sistemas Linux:
Termo | Descrição | Exemplo de Uso |
---|---|---|
ldd | Comando que exibe as dependências de bibliotecas compartilhadas de um executável ou script. | ldd /bin/ls Exibe as bibliotecas necessárias para o comando ls . |
ldconfig | Comando usado para atualizar o cache de bibliotecas compartilhadas do sistema e criar links simbólicos adequados. Ele é normalmente executado após a instalação de novas bibliotecas. | sudo ldconfig Atualiza a cache e os links simbólicos de bibliotecas compartilhadas. |
/etc/ld.so.conf | Arquivo de configuração que lista os diretórios adicionais onde o sistema deve procurar por bibliotecas compartilhadas. Direciona o ldconfig a incluir esses diretórios na cache. | – Adicionar /opt/myapp/lib ao /etc/ld.so.conf para incluir o diretório na busca de bibliotecas. |
LD_LIBRARY_PATH | Variável de ambiente que especifica diretórios adicionais onde o sistema deve procurar por bibliotecas compartilhadas, antes de procurar nos diretórios padrão. | export LD_LIBRARY_PATH=/opt/myapp/lib:$LD_LIBRARY_PATH Define um caminho adicional de bibliotecas para o sistema durante a sessão atual. |
comandos que usaremos nesse post:
- ls: Lista o conteúdo do diretório.
- cat: Concatena arquivos e exibe na saída padrão.
- sudo: Permite que o superusuário execute o comando com privilégios administrativos.
- ldconfig: Configura as ligações de tempo de execução do vinculador dinâmico.
- echo: Exibe o valor de uma variável ou texto na saída padrão.
- export: Exporta o valor de uma variável de ambiente para shells secundários.
- unset: Remove uma variável de ambiente.
- ldd: Exibe as dependências de objetos compartilhados de um programa.
- readelf: Exibe informações sobre arquivos ELF (Executable and Linkable Format).
- objdump: Exibe informações detalhadas sobre arquivos de objetos, como código de máquina e tabelas de símbolos.
Programas e bibliotecas compartilhadas
Para entender melhor sobre bibliotecas, precisamos considerar o processo de criação de programas. Um programa é desenvolvido usando uma linguagem de programação como C, C++, entre outras.
Após a criação, o código-fonte precisa ser transformado em um executável utilizável. O primeiro passo é a compilação, onde o compilador converte o código-fonte em código de máquina, resultando em arquivos-objeto.
Em seguida, o vinculador (linker) combina os arquivos-objeto e os vincula às bibliotecas necessárias para gerar o arquivo executável final.
Esse vínculo com bibliotecas é essencial porque, na maioria dos casos, os programas dependem de bibliotecas para fornecer funcionalidades adicionais e reutilizar código.
Uma biblioteca é um conjunto de códigos e funções pré-escritas, existentes no sistema, que podem ser reutilizadas por programas criados por você. Uma biblioteca ajuda a economizar tempo e recursos, evitando que os desenvolvedores precisem reescrever código comum para tarefas frequentes, como manipulação de arquivos ou operações matemáticas.
A ligação entre as bibliotecas e os programas pode ser feita de maneira estática ou dinâmica. Quando feita de maneira estática, a biblioteca é estática 🙂 , quando feita de modo dinâmico então podemos falar de biblioteca compartilhada.
- Biblioteca Estática: É uma coleção de código que é incorporada diretamente no executável durante o processo de compilação. Isso resulta em um arquivo maior, mas independente, pois todas as funções necessárias estão integradas (dentro) ao programa, eliminando a necessidade de bibliotecas externas em tempo de execução.
- Biblioteca Compartilhada: Também conhecida como biblioteca dinâmica, é uma coleção de código que não é incluída no executável. Em vez disso, é carregada na memória em tempo de execução, permitindo que múltiplos programas usem a mesma biblioteca ao mesmo tempo. Isso economiza espaço e facilita a atualização das bibliotecas, mas requer que elas estejam disponíveis no sistema para o programa funcionar corretamente. apenas uma cópia da biblioteca é carregada na memória, quando ela é usada por vários programas. Aqui, o vinculador (linker) não copia nenhum código da biblioteca para o arquivo do programa.
Tempo de execução (ou runtime) refere-se ao período durante o qual um programa é executado no sistema, após ter sido compilado e iniciado. Durante o tempo de execução, o programa realiza suas operações, como processar dados, interagir com o usuário, acessar arquivos, e utilizar recursos do sistema. É nesse momento que bibliotecas dinâmicas podem ser carregadas, erros podem ocorrer, e o comportamento do programa é determinado de acordo com as condições do ambiente e entradas fornecidas.
O compilador transforma o código fonte em código de máquina, gerando arquivos-objeto.
O linker combina os arquivos-objeto e os vincula às bibliotecas para gerar o arquivo executável final.
As bibliotecas são incluídas diretamente no executável, resultando em um arquivo maior, mas independente de bibliotecas externas.
O executável é vinculado a bibliotecas compartilhadas carregadas em tempo de execução, resultando em um arquivo menor e facilitando a atualização das bibliotecas.
O conceito de bibliotecas compartilhadas não é exclusivo do Linux. No Windows, por exemplo, elas são chamadas de DLL (bibliotecas de vínculo dinâmico).
Convenções de nomenclatura para arquivos-objeto compartilhados
ESTRUTURA DE NOMES DE BIBLIOTECAS COMPARTILHADAS
soname (shared object name) é o termo usado para se referir ao nome de biblioteca compartilhada.
Um exemplo é libpthread.so.0
outro exemplo é glibc que no Debian GNU/Linux 9.9, seu arquivo se chama libc.so.6
Esse nome (soname) segue um padrão composto por 3 elementos ou partes:
- o nome da biblioteca que geralmente se inicia com lib
- so (que significa “shared object”, ou objeto compartilhado
- Número de versão da biblioteca
ESTRUTURA DE NOMES DE BIBLIOTECAS ESTÁTICA
os nomes das bibliotecas estáticas terminam em .a, por exemplo libpthread.a.
Lista com alguns exemplos de bibliotecas compartilhadas e estáticas:
libc.so
(Compartilhada) – Funções básicas de C, como manipulação de strings e operações matemáticas.libm.so
(Compartilhada) – Funções matemáticas avançadas, como trigonometria e logaritmos.libgtk-3.so
(Compartilhada) – Criação de interfaces gráficas de usuário (GUI) para aplicativos GTK.libssl.so
(Compartilhada) – Implementação de protocolos de criptografia SSL/TLS para segurança de comunicação.libcurl.so
(Compartilhada) – Transferência de dados com URLs através de diversos protocolos.libsqlite3.so
(Compartilhada) – Gerenciamento de bancos de dados SQLite, permitindo operações de banco de dados leves.libpng.a
(Estática) – Manipulação de imagens no formato PNG, incluindo leitura e escrita de arquivos PNG.libcrypto.a
(Estática) – Implementação de algoritmos criptográficos usados pelo OpenSSL para segurança de dados.
PASTAS COMUNS DE BIBLIOTECAS
Diretórios de Bibliotecas em Sistemas Linux
Abaixo estão alguns diretórios comuns onde as bibliotecas são armazenadas:
/lib
: Armazena bibliotecas essenciais compartilhadas usadas pelo sistema operacional e por programas básicos. Também pode incluir algumas bibliotecas estáticas. Exemplo:libc.so
(compartilhada),libm.a
(estática)./lib32
: Utilizado em sistemas de 64 bits para armazenar bibliotecas compartilhadas de 32 bits necessárias para compatibilidade com aplicativos de 32 bits. Pode também conter bibliotecas estáticas de 32 bits. Exemplo:libgtk-x11-2.0.so
(compartilhada)./lib64
: Destinado a bibliotecas compartilhadas de 64 bits usadas em sistemas operacionais de 64 bits. Pode incluir algumas bibliotecas estáticas de 64 bits, embora seja mais comum encontrar bibliotecas compartilhadas aqui. Exemplo:libssl.so
(compartilhada)./usr/lib
: Abriga bibliotecas compartilhadas usadas por aplicativos instalados, além de algumas bibliotecas estáticas. Exemplo:libcurl.so
(compartilhada),libfoo.a
(estática)./usr/local/lib
: Guarda bibliotecas compartilhadas e estáticas instaladas manualmente por administradores ou usuários, fora do gerenciamento padrão de pacotes. Exemplo:libmycustomlib.so
(compartilhada),libmylib.a
(estática).
Alterando os caminhos da biblioteca compartilhada
Os programas que usam bibliotecas compartilhadas, ao serem abertos, têm as bibliotecas abertas pelo linker (vinculador), ou seja, o link é quem abre as bibliotecas referenciadas.
ld.so (ou ld-linux.so em sistemas Linux de 64 bits) é o carregador de bibliotecas dinâmicas do sistema operacional Linux. Sua principal função é carregar as bibliotecas compartilhadas necessárias para a execução de um programa e resolver as dependências dessas bibliotecas.
O vinculador busca por bibliotecas dentro de pastas listadas em /etc/ld.so.conf e em nos arquivos dentro de /etc/ld.so.conf.d.
Normalmente, /etc/ld.so.conf possui somente uma linha “include” para os arquivos com nomes terminados em .conf dentro de /etc/ld.so.conf.d
$ cat /etc/ld.so.conf
include /etc/ld.so.conf.d/*.conf
O diretório /etc/ld.so.conf.d contém arquivos *.conf:
elder@debian12:~$ ls /etc/ld.so.conf.d/ fakeroot-x86_64-linux-gnu.conf libc.conf x86_64-linux-gnu.conf
Esses arquivos *.conf devem incluir os caminhos absolutos para os diretórios da biblioteca
compartilhada:
elder@debian12:~$ cat /etc/ld.so.conf.d/x86_64-linux-gnu.conf # Multiarch support /usr/local/lib/x86_64-linux-gnu /lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu
LDCONFIG
O comando ldconfig
é utilizado para atualizar a cache das bibliotecas compartilhadas e criar os links simbólicos necessários para o correto funcionamento das aplicações que dependem dessas bibliotecas. Ele lê as configurações dos diretórios onde as bibliotecas estão armazenadas (geralmente especificados em /etc/ld.so.conf
e seus arquivos incluídos em /etc/ld.so.conf.d/) e atualiza o arquivo de cache /etc/ld.so.cache
.
Veja alguns exemplos de uso de ldconfig
:
Comando | Descrição |
---|---|
ldconfig | Atualiza o cache de bibliotecas e cria os links simbólicos necessários a partir de /etc/ld.so.conf . |
ldconfig -v | Executa o ldconfig em modo verboso, exibindo detalhes do processo. |
ldconfig -n /lib | Atualiza apenas os links simbólicos em /lib , sem atualizar o cache. |
ldconfig -N | Atualiza apenas o cache de bibliotecas, sem mexer nos links simbólicos. |
ldconfig -p | Exibe o cache atual das bibliotecas compartilhadas. |
ldconfig -f /custom/ld.so.conf | Usa o arquivo /custom/ld.so.conf como configuração alternativa para atualizar o cache. |
ldconfig -r /mnt/chroot | Atualiza o cache de bibliotecas e links simbólicos em um sistema montado em chroot no diretório /mnt/chroot . |
ldconfig
veja trecho de um exemplo de ldconfig -v
elder@debian12:~$ sudo ldconfig -v libnss_files.so.2 -> libnss_files.so.2 libmemusage.so -> libmemusage.so liblsan.so.0 -> liblsan.so.0.0.0 libargon2.so.1 -> libargon2.so.1 libnss_systemd.so.2 -> libnss_systemd.so.2 libfreetype.so.6 -> libfreetype.so.6.18.3 libunwind-x86_64.so.8 -> libunwind-x86_64.so.8.0.1 libm.so.6 -> libm.so.6 ...
podemos ver, por exemplo, como liblsan.so.0 está vinculado ao arquivo-objeto real compartilhado liblsan.so.0.0.0
LD_LIBRARY_PATH
O LD_LIBRARY_PATH
é uma variável de ambiente no Linux que especifica diretórios adicionais onde o sistema deve procurar por bibliotecas compartilhadas (arquivos .so
) durante a execução de programas. Ela é usada para sobrescrever as configurações padrão, permitindo que um programa encontre bibliotecas em locais não padrão.
LD_LIBRARY_PATH
, as letras “L” e “D” têm os seguintes significados:
- L: Refere-se a “Library,” ou seja, bibliotecas.
- D: Refere-se a “Directory,” ou seja, diretórios.
Para adicionar um caminho à essa variável faça assim:
$ LD_LIBRARY_PATH=/usr/local/mylib
para validar o valor que acabamos de armazenar dentro da variável, execute echo $LD_LIBRARY_PATH:
$ echo $LD_LIBRARY_PATH
/usr/local/mylib
Esse tipo de armazenamento que fizemos acima fica disponível apenas para o usuário/shell atual. Para fazer ficar disponível para qualquer outro processo use “export”:
$ export LD_LIBRARY_PATH=/usr/local/mylib
Para remover a variável de ambiente LD_LIBRARY_PATH, basta digitar “unset”:
$ unset LD_LIBRARY_PATH
Se quiser tornar as alterações permanentes, escrevemos a linha abaixo dentro de um dos scripts de inicialização do Bash, como /etc/bash.bashrc ou ~/.bashrc.
dependências de um executável específico
Use ldd para buscar as bibliotecas compartilhadas requeridas por um programa específico. O comando ldd deve vir seguido do caminho absoluto para o programa.
elder@debian12:~$ sudo ldd /usr/bin/ls linux-vdso.so.1 (0x00007ffeeb388000) libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f37edd0c000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f37edb24000) libpcre2-8.so.0 => /lib/x86_64-linux-gnu/libpcre2-8.so.0 (0x00007f37eda84000) /lib64/ld-linux-x86-64.so.2 (0x00007f37edd6c000)
Acima temos o caminho do arquivo da biblioteca compartilhada e o endereço de memória hexadecimal
Também, podemos usar ldd para procurar as dependências de uma biblioteca compartilahda (objeto compartilhado)
elder@debian12:~$ sudo ldd /lib/x86_64-linux-gnu/libselinux.so.1 linux-vdso.so.1 (0x00007ffe44728000) libpcre2-8.so.0 => /lib/x86_64-linux-gnu/libpcre2-8.so.0 (0x00007ffa5783c000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffa57654000) /lib64/ld-linux-x86-64.so.2 (0x00007ffa57914000)
Podemos usar -u ou –unused para exibir bibliotecas não usadas
elder@debian12:~$ sudo ldd -u /usr/bin/ls
A razão para haver dependências não utilizadas está relacionada às opções usadas pelo vinculador (linker) ao criar o binário.
Pode acontecer do programa não precisar da biblioteca mas ela ainda ficar rotulada como necessária (NEEDED) nas informações do arquivo-objeto. Podemos usar readelf ou objdump que servem para inspecionar arquivos binários.
readelf
exibe informações detalhadas sobre arquivos ELF (Executable and Linkable Format), que é o formato padrão de arquivos binários no Linux. Ele permite inspecionar vários aspectos de um arquivo ELF, como cabeçalhos, tabelas de símbolos, seções, e muito mais.objdump
é uma ferramenta mais geral que pode ser usada para inspecionar não apenas arquivos ELF, mas também outros tipos de arquivos binários. Além de fornecer informações detalhadas, comoreadelf
, ele também pode desassemblar o código de um arquivo, mostrando o código de máquina correspondente.
Desassemblar é o processo de converter código de máquina, que é executável pelo processador, de volta para uma representação em linguagem assembly, que é mais legível para humanos. Essa prática é usada para analisar o funcionamento interno de programas, depurar código, ou entender melhor um binário quando o código-fonte original não está disponível.
elder@debian12:~$ readelf -h /usr/bin/ls
elder@debian12:~$ objdump -a /usr/bin/ls
elder@debian12:~$ objdump -d /usr/bin/ls