3.12. Formatos binarios

Para entender por qué FreeBSD utiliza el formato elf(5), primero debe saber unas cuantas cosas sobre los tres formatos de ejecutables “dominantes” en UNIX®:

FreeBSD viene del campo “clásico” y ha utilizado el formato a.out(5), una tecnología usada y probada en muchas de muchas generaciones de versiones de BSD hasta el inicio de la rama 3.X. Aunque era posible compilar y ejecutar binarios nativos ELF (y kernels) en un sistema FreeBSD desde algún tiempo antes de esto, FreeBSD al principio se mantuvo “contra corriente” y no cambió a ELF como formato por defecto. ¿Por qué? Bueno, cuando el mundo Linux efectuó su dolorosa transición a ELF no fué tanto por huir del formato a.out como por su inflexible mecanismo de bibliotecas compartidas basado en tablas de saltos, que hacía igual de difícil la construcción de bibliotecas compartidas tanto para los desarrolladores como para los proveedores. Ya que las herramientas ELF disponibles ofrecían una solución al problema de las bibliotecas compartidas y eran vistas por mucha gente como “la manera de avanzar”, el costo de migración fué aceptado como necesario y se realizó la transición. El mecanismo de bibliotecas compartidas de FreeBSD está diseñado de manera más cercana al estilo del sistema de bibliotecas compartidas de SunOS™ de Sun y, como tal, es muy sencillo de utilizar.

Entonces, ¿por qué existen tantos formatos diferentes?

En un tiempo muy, muy lejano, existía hardware simple. Este hardware tan simple soportaba un sistema pequeño, simple. a.out era idóneo para el trabajo de representar binarios en este sistema tan simple (un PDP-11). A medida que la gente portaba UNIX desde este sistema simple, retuvieron el formato a.out debido a que era suficiente para los primeros portes de UNIX a arquitecturas como 68k de Motorola, VAXen, etc.

Entonces algún brillante ingeniero de hardware decidió que si podía forzar al software a hacer algunos trucos sucios podría sortear ciertos obstáculos del diseño y permitir al núcleo de su CPU correr más rápidamente. Aunque estaba hecho para trabajar con este nuevo tipo de hardware (conocido entonces como RISC), a.out no estaba bien adaptado para este hardware, así que varios formatos fueron desarrollados para obtener un mejor rendimiento de este hardware que el limitado, simple formato a.out podría ofrecer. Así fué cómo COFF, ECOFF y algunos otros formatos más extraños fueron inventados y sus limitaciones exploradas hasta que se fué llegando a la elección en favor de ELF.

Además, el tamaño de los programas estaba volviendose gigantes y los discos (y la memoria física) eran relativamente pequeños, así que el concepto de una biblioteca compartida nació. El sistema VM también se volvió más sofisticado. Mientras cada uno de estos avances fué hecho utilizando el formato a.out, su utilidad se iba reduciendo paulatinamente con cada nueva opción. Además, la gente quería cargar cosas dinámicamente en el momento de ejecución, o descartar partes de su programa después de que el código de inicio se ejecutara para ahorrar memoria principal y espacio de swap. Al volverse más sofisticados los lenguajes, la gente empezó a ver la necesidad de introducir código antes del inicio del programa de forma automática. Se hicieron muchos hacks al formato a.out para permitir que todas estas cosas sucedieran, y lo cierto es que por un tiempo funcionaron. Pero a.out no estaba no estaba para solucionar todos estos problemas sin incrementar la carga y complejidad del código. Aunque ELF resolvía muchos de estos problemas, en ese momento hubiera sido terrible dejar de lado un sistema que sencillamente funcionaba, así que ELF tuvo que esperar hasta que fué más doloroso permanecer con a.out que migrar a ELF.

De todas maneras, con el paso del tiempo, las herramientas de construcción de las que FreeBSD derivó las suyas propias (el ensamblador y el cargador, sobre todo) evolucionaron en dos árboles paralelos. El árbol FreeBSD añadió bibliotecas compartidas y corrigió algunos errores. La gente de GNU que originalmente escribió estos programas los reescribió y añadieron una forma más simple para disponer de compiladores cruzados (“cross compilers”), usando diferentes formatos a voluntad, etc. Aunque mucha gente quería compiladores cruzados con FreeBSD como blanco no estaban de suerte, porque los fuentes que FreeBSD tenía para as y ld no estaban listos para cumplir esa tarea. La nueva cadena de herramientas GNU (binutils) soporta compilación cruzada, ELF, bibliotecas compartidas, extensiones C++, etc. Además, muchos proveedores están liberando binarios ELF, y es algo muy bueno que FreeBSD los pueda ejecutar.

ELF es más expresivo que a.out y permite un sistema base más extensible. Las herramientas ELF están mejor mantenidas y ofrecen soporte de compilación cruzada, muy importante para mucha gente. ELF puede ser un poco más lento que a.out, pero tratar de medirlo puede ser difícil. También existen numerosos detalles que son diferentes entre los dos en cómo mapean páginas, cómo gestionan código de inicio, etc. Ninguno de estos es muy importante, pero existen diferencias. Con el tiempo, el soporte para a.out será eliminado del kernel GENERIC, y es muy posible que se elimine del kernel la posibilidad de ejecutar tales binarios una vez que la necesidad de usar programas a.out haya pasado.

Éste y otros documentos pueden obtenerse en ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

Para preguntas acerca de FreeBSD, leer la documentación antes de contactar con la lista <questions@FreeBSD.org>.
Para preguntas acerca de esta documentación, e-mail a <doc@FreeBSD.org>.