
Arquitectura de máquina minimalista con backend de compilador LLVM, puerto Linux y máquina virtual para crear cápsulas de software autocontenidas que permanezcan ejecutables indefinidamente sin dependencias complejas.
Este es el repositorio raíz de la Eternal Software Initiative.
La ESI define una arquitectura de máquina mínima (basada en una modificación del OISC Subleq) que es tan simple que su especificación completa puede ser escrita en una servilleta. Luego proporcionamos un backend de compilador LLVM para esta arquitectura, un port de Linux, ports de las bibliotecas de tiempo de ejecución de C/C++, y otras herramientas (incluyendo una implementación de máquina virtual de referencia en ~50 líneas de C) necesarias para construir y ejecutar una 'cápsula' autocontenida a partir de software existente.
¿Cuál es el propósito de todo esto? Ejecutar el software actual requiere una compleja pila de dependencias (compiladores, bibliotecas, frameworks, SO) sobre hardware propietario e incompletamente documentado, lo que hace muy difícil asegurar que el software actual siga funcionando en el futuro. Este problema de 'bit rot' (podredumbre de bits) es bien conocido por cualquiera que mantenga software heredado durante un período de años o décadas, pero ahora imagina a un historiador dentro de 1.000 años intentando entender la vida del siglo XXI, gran parte de la cual se experimenta a través del software. Incluso si los binarios del software actual se conservan, es descabellado imaginar que esos binarios sigan siendo ejecutables. Emuladores como QEMU trasladan este problema pero no lo resuelven: ellos también tienen una pila igualmente compleja de dependencias de software y hardware, por lo que tampoco serán ejecutables en el futuro lejano.
La ESI resuelve este problema mediante (1) la definición de una arquitectura que es lo suficientemente simple como para escribirla en una servilleta pero lo suficientemente potente como para representar eficientemente cualquier software, y que no requiere conocimiento de ningún hardware, software, framework propietario, etc., y (2) la implementación de una cadena de herramientas para compilar cualquier software existente en una 'cápsula' autocontenida para esta arquitectura. Esto asegura que, siempre que se conserven el binario de la cápsula y las instrucciones de la servilleta, el software pueda ser revivido y experimentado en el futuro lejano sin asumir ningún conocimiento de los sistemas informáticos actuales.
Este repositorio incluye todo lo necesario para construir y ejecutar tu propia máquina ESI, y construir 'cápsulas' ESI a partir de software existente.
Para más información sobre la misión de la ESI, consulta: https://www.eternal-software.org
Este repositorio incluye, como submódulos, forks ESI de la cadena de herramientas LLVM, el kernel de Linux, uClibc-ng y Busybox. Todos ellos deben ser clonados juntos.
git clone --recurse-submodules https://github.com/adriancable/eternal
Necesitarás SDL3 para construir la máquina virtual ESI. Instálalo con, por ejemplo, apt install libsdl3-dev. No hay otras dependencias. SDL3 puede reemplazarse fácilmente por cualquier otro medio para escribir píxeles y capturar eventos de teclado, ahora o en el futuro.
cd eternal/vm
make
xz -d ../capsules/vmlinux.bootimage.xz
./vm ../capsules/vmlinux.bootimage
Cuando Linux haya arrancado, prueba por ejemplo:
cd doom
./doom
La cadena de herramientas ESI debería construirse en cualquier sistema Linux con un esfuerzo mínimo. También hemos construido con éxito en macOS, con algunas modificaciones. Asegúrate de tener gcc, python3, CMake, ninja, flex, bison instalados y operativos.
Comienza en la carpeta eternal clonada.
rm -rf llvm-project/build && mkdir -p llvm-project/build
cmake -G Ninja -S llvm-project/llvm -B llvm-project/build -DLLVM_ENABLE_PROJECTS="clang;lld" -DLLVM_BUILD_TOOLS=ON -DLLVM_ENABLE_ASSERTIONS=OFF -DCMAKE_BUILD_TYPE=Release -DLLVM_TARGETS_TO_BUILD="" -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD="Subleq" -DLLVM_DEFAULT_TARGET_TRIPLE="subleq-unknown-linux" -DLLVM_FORCE_VC_REPOSITORY="ESI" -DLLVM_FORCE_VC_REVISION=""
cd llvm-project/build
ninja llc clang llvm-mc lld llvm-objcopy llvm-ar llvm-ranlib llvm-nm llvm-readelf llvm-strip llvm-objdump
cd ../../linux
make ARCH=subleq \
CC=../llvm-project/build/bin/clang \
LD=../llvm-project/build/bin/ld.lld \
AR=../llvm-project/build/bin/llvm-ar \
NM=../llvm-project/build/bin/llvm-nm \
OBJCOPY=../llvm-project/build/bin/llvm-objcopy \
INSTALL_HDR_PATH=../runtime/sysroot/kernel-headers \
headers_install
cd ../uclibc-ng
make ARCH=subleq defconfig
make ARCH=subleq \
CC=../llvm-project/build/bin/clang \
LD=../llvm-project/build/bin/ld.lld \
AR=../llvm-project/build/bin/llvm-ar \
NM=../llvm-project/build/bin/llvm-nm \
PREFIX=../runtime/sysroot \
STRIPTOOL=../llvm-project/build/bin/llvm-strip \
DEVEL_PREFIX=/ \
install_dev
cd ../runtime
./build_and_install_runtime.sh
./build_libcxx.sh
ninja -C ./libcxx install
cd ../busybox
make subleq_defconfig
make CC=../llvm-project/build/bin/clang \
AR=../llvm-project/build/bin/llvm-ar \
STRIP=../llvm-project/build/bin/llvm-strip
mkdir ../initramfs_root/bin
cp busybox ../initramfs_root/bin/busybox
cd ../linux
export KBUILD_BUILD_USER="root"
export KBUILD_BUILD_HOST="eternal"
make ARCH=subleq \
CC=../llvm-project/build/bin/clang \
LD=../llvm-project/build/bin/ld.lld \
AR=../llvm-project/build/bin/llvm-ar \
NM=../llvm-project/build/bin/llvm-nm \
OBJCOPY=../llvm-project/build/bin/llvm-objcopy \
defconfig
make ARCH=subleq \
CC=../llvm-project/build/bin/clang \
LD=../llvm-project/build/bin/ld.lld \
AR=../llvm-project/build/bin/llvm-ar \
NM=../llvm-project/build/bin/llvm-nm \
OBJCOPY=../llvm-project/build/bin/llvm-objcopy
cd ..
python3 tools/make_boot_image.py --stack-size 536870912 linux/vmlinux
./vm/vm linux/vmlinux.bootimage
Escribe exit cuando termines para terminar la VM.
Flujo de trabajo estándar de compilación cruzada. Para empezar rápidamente, proporcionamos un script de conveniencia (clang_userspace.sh) que configura el entorno y llama a clang.
cat << 'EOF' > hello.c
#include <stdio.h>
int main() {
printf("Hello, ESI world!\n");
return 0;
}
EOF
tools/clang_userspace.sh hello.c
cp hello.elf initramfs_root/root
Luego reconstruye el initramfs y la cápsula:
cd linux
make ARCH=subleq \
CC=../llvm-project/build/bin/clang \
LD=../llvm-project/build/bin/ld.lld \
AR=../llvm-project/build/bin/llvm-ar \
NM=../llvm-project/build/bin/llvm-nm \
OBJCOPY=../llvm-project/build/bin/llvm-objcopy
cd ..
python3 tools/make_boot_image.py --stack-size 536870912 linux/vmlinux
Arranca la VM:
./vm/vm linux/vmlinux.bootimage
Una vez que Linux haya arrancado:
./hello.elf
Proporcionada para que los desarrolladores actuales entiendan la arquitectura y la cadena de herramientas. Nada de esto (excepto la servilleta) es necesario para que alguien dentro de 1.000 años reviva una cápsula y ejecute el software que contiene.