10.8. Temas avanzados

Si siente curiosidad por saber cómo funciona la compatibilidad con Linux esta es la sección que debe leer. La mayor parte de lo que sigue está basado casi en su totalidad en un mensaje enviado por Terry Lambert a la lista lista de charla de FreeBSD (Message ID: <199906020108.SAA07001@usr09.primenet.com>).

10.8.1. ¿Cómo funciona?

FreeBSD dispone de una abstracció denominada “cargador de clase en ejecución”. Esto no es más que un bloque de có:digo incrustado en la llamada execve(2) del sistema.

Históricamente las plataformas UNIX® disponían de un único cargador de binarios, que en última instancia (fallback) recurría al cargador #! para ejecutar cualesquiera intérpretes o scripts de la shell. Ese cargador único examinaba el número mágico (generalmente los 4 u 8 primeros bytes del fichero) para ver si era un binario reconocible por el sistema y, en tal caso, invocaba al cargador binario.

Si no era de tipo binario, la llamada execve(2) devolvía un error y la shell intentaba empezar a ejecutarlo como órdenes shell, tomando por defecto como punto de partida “la shell actual, sea cual sea”.

Posteriormente se pensó en hacer una modificación de manera que sh(1) examinara los dos primeros caracteres, de modo que si eran :\n se llamaba a la shell csh(1) en su lugar (parece ser que en SCO fueron los primeros en utilizar ese truco).

Lo que ocurre ahora es que FreeBSD dispone de una lista de cargadores, en lugar de uno solo. FreeBSD recorre esa lista de cargadores, con un cargador genérico #! que sabe reconocer los intérpretes en base a los caracteres que siguen al siguiente espacio en blanco, con /bin/sh como último recurso.

Para dar soporte a la ABI (“Application Binary Interface”) de Linux, FreeBSD interpreta el número mágico como un binario ELF (“Executable and Linking Format”): En este punto no hace distinción entre FreeBSD, Solaris™, Linux® o cualquier otro SO que tenga un tipo de imagen ELF.

El cargador ELF busca entonces una marca (brand) especial, una sección de comentarios en la imagen ELF que no está presente en los binarios ELF de SVR4/Solaris.

Para que los binarios de Linux funcionen deben estar marcados con brandelf(1) como tipo Linux:

# brandelf -t Linux file

Hecho esto el cargador ELF verá la marca Linux en el fichero.

Cuando el cargador ELF ve la marca Linux sustituye un puntero en la estructura proc. Todas las llamadas del sistema se indexan a través de este puntero (en un sistema UNIX tradicional sería el «array» de estructura sysent[] que contiene las llamadas del sistema). Además, el proceso se marca con unos indicadores (“flags”) para que el vector trampa del código de envío señales lo maneje de una forma determinada, así como otros arreglos (menores) que serán utilizados por el módulo Linux del kernel.

El vector de llamada del sistema Linux contiene, entre otras cosas, una lista de entradas sysent[] cuyas direcciones residen en el módulo del kernel.

Cuando el binario Linux realiza una llamada al sistema, el código trampa extrae el puntero a la función de la llamada del sistema de la estructura proc, y así obtiene los puntos de entrada a las llamadas del sistema Linux, no las de FreeBSD.

Además, el modo Linux cambia la raíz de las búsquedas de una forma dinámica. En efecto, esto es lo que hace la opción union cuando se monta un sistema de ficheros (¡y que no es lo mismo que el sistema de ficheros unionfs!). Primero se hace un intento de buscar el fichero en el directorio /compat/linux/ruta-original y solo después, si lo anterior falla, se repite la búsqueda en el directorio /ruta-original. Esto permite que se puedan ejecutar binarios que necesitan de otros binarios (por ejemplo las herramientas de programación (“toolchain”) de Linux pueden ejecutarse en su totalidad bajo la ABI de Linux). Esto significa también que los binarios Linux pueden cargar y ejecutar binarios FreeBSD si los binarios Linux equivalentes no se hallan presentes y que se puede poner una orden uname(1) en el árbol de directorios /compat/linux para poder estar seguros de que los binarios Linux no puedan decir que no estaban ejecutándose en Linux.

En efecto, hay un kernel Linux en el kernel FreeBSD; las distintas funciones subyacentes que implementan todos los servicios proporcionados por el kernel son idénticas en ambas, las tablas de entradas de llamadas del sistema en FreeBSD y en Linux: operaciones del sistema de ficheros, operaciones de memoria virtual, envío de señales IPC System V, etc. La única diferencia es que los binarios FreeBSD reciben sus funciones de conexión (“glue”) y los binarios Linux las suyas (la mayoría de los sistemas operativos más antiguos solo tienen sus propias funciones de conexión: direcciones de funciones en un “array” de estructura sysent[] estática y global, en lugar de direcciones de funciones que se extraen a partir de un puntero inicializado dinámicamente en la estructura proc del proceso que hace la llamada).

¿Cuál es entonces la ABI nativa de FreeBSD? No importa. Básicamente, la única diferencia es (ahora mismo; esto podría cambiar y probablemente lo hará en una release futura) que las funciones de conexión de FreeBSD están enlazadas estáticamente en el kernel mientras que las de Linux pueden estarlo también estáticamente o se puede acceder a ellas por medio de un módulo del kernel.

Bien, pero ¿de verdad es esto una emulación? No. Es una implementación ABI, no una emulación. No hay un emulador involucrado (ni un simulador, para adelantarnos a la siguiente pregunta).

Entonces ¿por qué a veces se le llama “emulación Linux”? ¡Para hacer más difícil el vender FreeBSD! En serio, se debe a que la primera implementación se hizo en un momento en que realmente no había ninguna palabra distinta a esa para describir lo que se estaba haciendo; decir que FreeBSD ejecutaba binarios Linux no era cierto si no se compilaba el código o se cargaba un módulo; hacía falta una forma de describir todo esto y acabamos usando “emulador Linux”.

Puede descargar éste y muchos otros documentos desde ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

Si tiene dudas sobre FreeBSD consulte la documentación antes de escribir a la lista <questions@FreeBSD.org>.
Envíe sus preguntas sobre la documentación a <doc@FreeBSD.org>.