LinuxTutoriales

Formato ELF de Linux: qué es

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.

Te recomiendo leer sobre los tipos de archivos que existen

Qué es un EFL

a.out 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

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ágica 0x7F '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.
  • .plt y .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

Carga de memoria en Linux

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…

Isaac

Geek de los sistemas electrónicos, especialmente del hardware informático. Con alma de escritor y pasión por compartir todo el conocimiento sobre tecnología.
Los datos de carácter personal que nos facilite mediante este formulario quedarán registrados en un fichero de Miguel Ángel Navas Carrera, con la finalidad de gestionar los comentarios que realizas en este blog. La legitimación se realiza a través del consentimiento del interesado. Si no se acepta no podrás comentar en este blog. Puedes consultar Política de privacidad. Puede ejercitar los derechos de acceso, rectificación, cancelación y oposición en info@profesionalreview.com
Botón volver arriba