O utilitário readelf é uma ferramenta essencial no ecossistema Linux para engenheiros de sistemas e desenvolvedores que precisam inspecionar o conteúdo de arquivos no formato ELF (Executable and Linkable Format). Diferente de ferramentas como o objdump, o readelf não depende da BFD (Binary File Descriptor library), o que permite uma visualização direta das estruturas de dados conforme definidas na especificação ELF.
Extração Completa de Metadados
Para obter uma visão abrangente de todas as seções, cabeçalhos e tabelas contidas em um binário, utiliza-se a flag -a. Este comando consolida as informações mais relevantes do arquivo.
readelf -a modulo_sistema.so
A saída inicial apresenta o ELF Header, que contém a "certidão de nascimento" do binário:
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64 # Arquivo de 64 bits
Data: 2's complement, little endian # Formato Little Endian
Version: 1 (current) # Versão atual do ELF
OS/ABI: UNIX - System V # Interface padrão UNIX
ABI Version: 0
Type: DYN (Shared object file) # Biblioteca compartilhada (.so)
Machine: Advanced Micro Devices X86-64 # Arquitetura Alvo
Entry point address: 0x8ce0 # Endereço de entrada
Start of program headers: 64 (bytes)
Number of section headers: 35
Identificação da Versão do Compilador
Muitas vezes é necessário validar com qual versão do GCC ou Clang um binário foi gerado. O readelf permite extrair essas strings da seção .comment.
readelf -p .comment binario_executavel
O resultado revela informações sobre o ambiente de build:
String dump of section '.comment':
[ 0] GCC: (GNU) 10.2.1 20210130 (Red Hat 10.2.1-11)
Análise de Dependências Dinâmicas
Para verificar quais bibliotecas externas o binário solicita em tempo de execução, bem como outras informações da seção dinâmica, utiliza-se a flag -d.
readelf -d libengine.so
As entradas marcadas como (NEEDED) indicam as dependências diretas de bibliotecas compartilhadas:
Dynamic section at offset 0x18d98 contains 30 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libpthread.so.0]
0x0000000000000001 (NEEDED) Shared library: [libstdc++.so.6]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000c (INIT) 0x7e00
0x000000000000001a (FINI_ARRAY) 0x218d50
Inspeção da Tabela de Símbolos
A tabela de símbolos contém os nomes de funções e variáveis manipuladas pelo binário. Para visualizar tanto os símbolos internos quanto os exportados, utiliza-se -s.
readelf -s aplicativo_core
Se o objetivo for filtrar apenas os símbolos dinâmicos (aqueles necessários para a linkagem em tempo de execução), o parâmetro --dyn-syms é o mais indicado:
readelf --dyn-syms aplicativo_core
Abaixo, um exemplo da estrutura de saída para símbolos dinâmicos:
Symbol table '.dynsym' contains 285 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND malloc@GLIBC_2.2.5
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND free@GLIBC_2.2.5
3: 00000000000012a0 45 FUNC GLOBAL DEFAULT 12 custom_init_func
4: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
Nesta tabela, a coluna Ndx com o valor UND indica símbolos indefinidos que o binário espera encontrar em outras bibliotecas compartilhadas no momento da execução.