El problema fundamental que Kakehashi aborda es la portabilidad de binarios entre sistemas operativos con arquitecturas de CPU idénticas pero ABIs de sistema diferentes. Específicamente, permite que ejecutables compilados para macOS ARM64 (Darwin) se ejecuten en Linux aarch64. Esto es relevante en el contexto actual de la creciente adopción de la arquitectura ARM64 en servidores y dispositivos, donde la fragmentación de los entornos de ejecución (macOS vs. Linux) presenta un desafío para la reutilización de artefactos binarios y la optimización de costes de infraestructura.
Tradicionalmente, la ejecución de binarios de un sistema operativo en otro ha requerido emulación de CPU (como QEMU) o capas de compatibilidad complejas a nivel de sistema operativo (como Wine para Windows en Linux, o Darling para macOS en Linux). Kakehashi se posiciona como una solución más ligera para el caso específico de ARM64, donde la arquitectura de la CPU es la misma, eliminando la necesidad de emulación de instrucciones y centrándose en la traducción de la interfaz de llamadas al sistema (syscalls) y el entorno de tiempo de ejecución.
La motivación principal detrás de Kakehashi es económica y operativa: reducir los costos de infraestructura de CI/CD al permitir que las cargas de trabajo de macOS CLI se ejecuten en runners de Linux aarch64, que son significativamente más baratos que los runners de macOS. Esto conecta con el principio de optimización de recursos en sistemas distribuidos a gran escala, donde la eficiencia en el uso de la computación es crítica.
Arquitectura del Sistema
Kakehashi se compone de varios crates de Rust que colaboran para lograr la ejecución de binarios Mach-O de macOS en Linux aarch64. El componente central es kh-loader, responsable de parsear el formato Mach-O del binario de macOS, mapear sus segmentos en el espacio de direcciones del proceso de Linux y preparar el entorno de ejecución. Este loader interactúa con kh-runtime, que gestiona la memoria, las trampas de ejecución y, crucialmente, la traducción de las llamadas al sistema BSD (Darwin) a las llamadas al sistema Linux.
kh-runtime incluye una libSystem.B.dylib independiente (freestanding), compilada específicamente para aarch64-apple-darwin y embebida en el binario de Kakehashi. Esta libSystem proporciona las implementaciones de las funciones de la biblioteca estándar de macOS que los binarios de invitado esperan. Cuando un binario de macOS realiza una syscall, Kakehashi intercepta esta llamada, la traduce a su equivalente de Linux y la ejecuta. Esto implica un cambio de contexto (TLS switch, alt stack, NEON save/restore, Rust dispatch) que introduce una sobrecarga.
El sistema de archivos se gestiona a través de un 'bottle' (botella) que mapea rutas de invitado a rutas del host. Por ejemplo, /Volumes/linux/... en el invitado se traduce al sistema de archivos del host. Esto permite que los binarios de macOS accedan a los recursos del sistema de archivos de Linux de manera transparente. La configuración de OpenSSL y los certificados CA también se gestionan a través de este mapeo, permitiendo que curl de macOS realice solicitudes HTTPS en el entorno de Linux. Kakehashi no utiliza JIT (Just-In-Time compilation), lo que simplifica la arquitectura pero implica que la traducción de syscalls es un punto de contención de rendimiento.
Ejecución de Binario macOS en Linux aarch64
- 1 kh run <binario> El CLI de Kakehashi inicia el proceso.
- 2 kh-loader Parse Mach-O, mapea segmentos en espacio de direcciones de Linux.
- 3 kh-runtime Prepara el entorno de ejecución, carga `libSystem.B.dylib`.
- 4 Binario macOS Ejecuta código nativo en la CPU ARM64.
- 5 Syscall (Darwin) El binario realiza una llamada al sistema BSD.
- 6 kh-runtime (Intercept) Intercepta la syscall, traduce a equivalente de Linux.
- 7 Syscall (Linux) Ejecuta la syscall traducida en el kernel de Linux.
- 8 Resultado El resultado se devuelve al binario macOS.
| Capa | Tecnología | Justificación |
|---|---|---|
| orchestration | Docker/Colima | Provee un entorno de ejecución aislado y consistente para probar y desplegar Kakehashi en Linux aarch64. |
| compute | Rust | Lenguaje de programación principal para el desarrollo de Kakehashi, elegido por su seguridad de memoria y rendimiento, crucial para una capa de traducción de bajo nivel. vs C/C++ Rust 1.88+ |
| storage | Filesystem Abstraction (Bottle) | Mapea rutas del sistema de archivos del invitado (macOS) a rutas del host (Linux), permitiendo el acceso transparente a archivos y directorios. /Volumes/linux/... en invitado -> host FS |
| security | OpenSSL / CA Bundle | Permite que las aplicaciones de macOS (ej. curl) realicen conexiones HTTPS seguras, utilizando certificados CA del host o descargados. /etc/ssl/cert.pem mapeado desde el host |
Trade-offs
Ganancias
- ▲▲ Costo de infraestructura CI/CD
- ▲ Disponibilidad de runners CI
- ▲ Reutilización de binarios macOS CLI
Costes
- ▲ Rendimiento para cargas de trabajo intensivas en syscalls
- ▲ Compatibilidad con GUI/frameworks complejos de macOS
include_bytes!("crates/kh-runtime/resources/libSystem.B.dylib")Fundamentos Teóricos
El concepto de Kakehashi se alinea con los principios de la virtualización de sistemas operativos y las capas de compatibilidad de ABI (Application Binary Interface). Aunque no es una virtualización completa de hardware, comparte similitudes con la paravirtualización, donde el sistema operativo invitado es consciente de que no se está ejecutando directamente sobre el hardware, sino sobre una capa de abstracción. En este caso, el binario de macOS no es modificado, pero su entorno de ejecución es interceptado y adaptado.
El problema de la traducción de syscalls ha sido estudiado extensamente en el contexto de la compatibilidad de sistemas operativos, como se ve en proyectos como WINE (Wine Is Not an Emulator) para ejecutar aplicaciones de Windows en Linux, o en sistemas de compatibilidad de UNIX como los que permitían ejecutar binarios de Solaris en Linux. Estos sistemas a menudo se basan en la interceptación de llamadas al sistema (usando mecanismos como ptrace o LD_PRELOAD en Linux, o trampas de CPU) y la traducción de los argumentos y resultados entre las ABIs de los dos sistemas operativos. La eficiencia de esta traducción es un factor crítico, y la sobrecarga observada en Kakehashi para operaciones intensivas en I/O (como la compresión de múltiples archivos) es un recordatorio de los desafíos inherentes a la traducción de ABI en tiempo de ejecución, un tema recurrente en la investigación de sistemas operativos y rendimiento.