El formato ELF es un tipo de archivo estándar para ejecutables, código objeto, bibliotecas compartidas y volcados de memoria principal en sistemas operativos basados en Linux y otros sistemas tipo Unix. Entender su estructura es crucial para desarrolladores, ingenieros de sistemas y cualquier persona interesada en el funcionamiento interno de estos sistemas, ya que define cómo se organizan los programas en el almacenamiento y cómo se cargan en la memoria para su ejecución.
Índice de contenidos
Te recomiendo leer sobre los tipos de archivos que existen
Qué es un EFL
El formato ELF (Executable and Linkable Format) es el estándar utilizado por Linux y otros sistemas tipo UNIX para almacenar ejecutables, bibliotecas compartidas y objetos intermedios. Surgió como reemplazo de formatos más antiguos como a.out y COFF, ofreciendo mejoras importantes.
Si has trabajado con GCC en Linux, seguro que al compilar te encuentras un binario llamado a.out como resultado, si no has usado la opción -o para especificar un nombre. Pero no te asustes, no se trata de un a.out real, sino de un ELF. Es decir, el nombre a.out es un remanente histórico. Este nombre viene de las primeras versiones de Unix, donde era la abreviatura de «assembler output» (salida del ensamblador)…
Un archivo ELF describe cómo debe cargarse un programa o biblioteca en memoria para su ejecución o enlace. Dependiendo de su tipo, puede ser:
- Ejecutable: contiene código listo para ejecutarse, es decir, es un binario, como los .exe de Windows, u otros similares…
- Biblioteca compartida (.so): código reutilizable cargado en tiempo de ejecución.
- Objeto intermedio (.o): resultados de compilación que requieren enlace posterior.
ELF soporta arquitecturas como x86, x86_64, ARM, RISC-V, entre muchas otras.
Estructura del EFL
En cuanto a la estructura interna de un archivo ELF consta de tres grandes componentes:
- Cabecera ELF (ELF Header): contiene metadatos globales del archivo.
- Tabla de cabeceras de programa (Program Header Table): indica cómo se deben mapear los segmentos en memoria.
- Tabla de cabeceras de sección (Section Header Table): describe las secciones utilizadas en enlace y depuración.
Cabecera ELF
La cabecera ELF es la primera parte del archivo e incluye información como:
- Identificación
e_ident(marca mágica0x7F 'E' 'L' 'F'). - Tipo de archivo (ejecutable, biblioteca, objeto).
- Arquitectura objetivo (e.g., EM_X86_64 para binarios x86 de 64-bit).
- Offsets hacia las tablas de programa y de sección.
Estos campos permiten al cargador del sistema interpretar correctamente el resto del archivo.
Secciones y segmentos
Un segmento es una unidad que se carga en memoria, mientras que una sección es una división lógica utilizada para enlazar y depurar. Algunos ejemplos comunes:
.text: código ejecutable, es decir, el código del programa que la CPU deberá procesar..data: datos inicializados..bss: datos no inicializados..rodata: datos de solo lectura..plty.got: tablas para llamadas a funciones externas..symtab: tabla de símbolos..strtab: tabla de cadenas asociada a símbolos.
Tabla de símbolos y cadenas
La tabla de símbolos contiene estructuras que describen funciones y variables (nombre, dirección, tamaño, tipo). Sus nombres se almacenan en tablas de cadenas asociadas, como .strtab o .dynstr. Hay dos tipos principales:
.symtab: usada en enlazado y depuración (no siempre presente en ejecutables finales)..dynsym: usada en tiempo de ejecución para enlace dinámico.
Los EFL también usan un proceso de relocalización, es decir, un ajuste de las direcciones de memoria donde se carga el código y datos cuando no tienen especificadas posiciones fijas. Esta relocalización puede ser estática (en tiempo de enlace) o dinámica (en tiempo de ejecución).
También te puede interesar leer más sobre cómo funciona la ejecución en WINE
Carga en memoria
El cargador de Linux (ld-linux.so para ejecutables dinámicos) lee la cabecera del programa y carga los segmentos en memoria según sus permisos (lectura, escritura, ejecución). También inicializa las áreas de datos y prepara el entorno antes de transferir el control a la función _start, que comienza la ejecución.
Si quieres explorar más sobre ELF, te animo a utilizar herramientas como readelf, objdump, nm, file, y ldd, comandos que sirven respectivamente para ver la estructura interna, desensamblar el código, listar símbolos, identificar el tipo de archivo y mostrar bibliotecas dinámicas requeridas.
Variantes y extensiones del formato
Existen variantes de ELF adaptadas a sistemas embebidos, así como versiones «stripped» (sin tablas de símbolos) para reducir tamaño o proteger propiedad intelectual del código si se trata de un binario de un software propietario.
También hay extensiones específicas para arquitecturas como ARM, MIPS o RISC-V, que añaden tipos de relocalización y atributos adicionales específicas para estas ISAs.
No olvides dejar tus comentarios…


