Csmopolitan hace de C un lenguaje tip"compila una vez y abre donde sea", similar a Java, salvo que no requiere la instalación previa de intérpretes o máquinas virtuales. Cosmo proporciona los mismos beneficios de portabilidad que los lenguajes de alto nivel como Go y Rust, pero no inventa un nuevo lenguaje y no necesita configurar un sistema de CI para construir binarios separados para cada sistema operativo. En lo que se centra Cosmopolitan es en "corregir" C desvinculándolo de las plataformas con el fin de que sea universalmente distribuíble.
|
etiquetas: libreria , c , unix , linux , cosmopolitan , libc , ape , portable
Voy a leer a ver
Bueno, una vez leído no ofrece lo que promete la entradilla pero es interesante. No permite (como es lógico) compilar y ejecutar en cualquier parte, pero parece que si en distintos SO.
Pero como cambie la arquitectura...
EDITO: empiezo a intuir cómo va la cosa... y es una paja mental de cuidado
Eso con tinyemu.com. Aún así es asombroso.
Prueba a ejecutarlo en un ARM a ver, aunque sea el mismo S.O.
Francamente, no le veo ni remotamente el parecido con una JVM de Java.
El código máquina no tiene que ver con el SO, es común.
justine.lol/ape.html
MZqFpD='
BIOS BOOT SECTOR'
exec 7<> $(command -v $0)
printf '177ELF...LINKER-ENCODED-FREEBSD-HEADER' >&7
exec "$0" "$@"
exec qemu-x86_64 "$0" "$@"
exit 1
REAL MODE...
ELF SEGMENTS...
OPENBSD NOTE...
NETBSD NOTE...
MACHO HEADERS...
CODE AND DATA...
ZIP DIRECTORY...
Y luego lo explica, pero yo no entiendo nada...
justine.lol/ape.html
MZqFpD='
BIOS BOOT SECTOR'
exec 7<> $(command -v $0)
printf '177ELF...LINKER-ENCODED-FREEBSD-HEADER' >&7
exec "$0" "$@"
exec qemu-x86_64 "$0" "$@"
exit 1
REAL MODE...
ELF SEGMENTS...
OPENBSD NOTE...
NETBSD NOTE...
MACHO HEADERS...
CODE AND DATA...
ZIP DIRECTORY...
Y luego lo explica, pero yo no entiendo nada...
El nombre de la primera variable se codifica a ensamblador, luego dependiendo de quién lo carga, verá una variable shell o no...
Porqué la asigna a BIOS BOOT SECTOR? ... Parece que puede arrancar sin SO...
Qué narices es command?
Por otro lado, el código máquina tiene un punto en el que sí tiene que ver con el SO, que es la llamada para entrada/salida. En este caso parece que se aprovecha de que todos los sistemas son POSIX y utilizan SYSCALL para ello... excepto con DOS, que no se cómo lo hace. ¿FreeDOS tiene una minicapa de compatibilidad POSIX?
Se puede hacer entrada/salida sin llamar al SO accediendo al hardware directamente. De todos modos, aquí seguro que tiene una librería que incorpora una capa de compatibilidad enlazada estáticamente (esa libc, precisamente).
Que utilices el SO para hacer algo no hace al código máquina dependiente del SO. El código máquina es absolutamente independiente del sistema operativo, otra cosa es como lo utilices tú en tus programas.
Evidentemente si la compatibilidad es solo entre sistemas POSIX (que de hecho es un estándar) la cosa es mucho más fácil. Pero parece que funciona en DOS y Windows... eso necesita código específico. La verdad es que no se como lo hace, tampoco estoy al tanto de los sistemas de carga de ejecutables de los distintos S.O.
PD: #23 aporta un link con el misterio resuelto.
Misterio resuelto.
Muchas gracias.
Respecto al enlace ese, sí, dice cosas, pero no lo explica demasiado. Hay mucho que desenmarañar de lo que pone ahí para realmente entender cómo y por qué funciona.
La primera línea, si la codificamos en ensamblador, es un salto al código en sí. Esto hace que el fichero se ejecute como un .COM en DOS, que simplemente asume que si intentamos ejecutar un fichero .COM o .EXE que no tenga cabecera de .EXE, es un .COM, así que lo carga directamente en el offset 256 del segmento de código y lo ejecuta directamente desde el primer byte. Pero en un sistema UNIX este fichero se interpreta como un script de shell, por lo que las dos primeras líneas simplemente se interpretarán como una asignación a una variable de entorno llamada MZqFpD, por lo que podemos considerar que se ignoran en un sistema UNIX. En Windows, por lo que se, el formato PE de ejecutable es capaz de entender un fichero con un trozo de código para DOS al principio.
La tercera línea, el EXEC, normalmente lo que hace es ejecutar un binario reemplazando el código actual de la shell por el de ese binario. Pero si te fijas, en lugar de poner un comando a ejecutar, utiliza 7<>. Eso es una redirección (como cuando haces loquesea > fichero_de_salida), pero redirige tanto la entrada como la salida (<>) al identificador de fichero 7 (si recuerdas, el 0 es la entrada estándar, el 1 es la salida estándar, y el 2 es la salida estándar de error; de ahí para arriba pueden ser ficheros nuevos abiertos, pipes, etc. En este caso, como no pone un comando, lo que hace es redirigir el pipe con el identificador 7 a lo que diga "command -v $0". $0 es el primer parámetro con el que se ha llamado al programa, y siempre es el nombre del propio programa. Y "command -v nombredeunejecutable" devuelve la ruta de dicho ejecutable. Por tanto, redirige todo lo que se lea o escriba en dicho identificador al propio fichero ejecutable.
Ahora viene lo divertido: en la siguiente línea imprime '177ELF...LINKER-ENCODED-FREEBSD-HEADER', pero lo envía al pipe con identificador 7. Pero como ese pipe está redirigido al ejecutable, eso significa que está escribiendo esa línea en el propio fichero ejecutable. Y al usar >&7 en lugar de >7, por lo que he comprobado, lo que hace es sustituir los primeros bytes del propio fichero por esa cadena... Y como esa cadena es justo la cabecera de identificación de un fichero ELF, un ejecutable de UNIX, entonces lo que está haciendo es sobreescribir todo lo que había antes para convertirlo en un ELF. Claro, esto es irreversible, por lo que una vez que has ejecutado este programa en un UNIX, ya no funcionará en DOS.
Y después de esto, simplemente llama a EXEC con el propio fichero para que lo ejecute como un ELF nativo, pero si falla (porque intentamos ejecutar un binario de x86 en un ARM, por ejemplo) entonces utiliza qemu para ejecutarlo. Y si esto también falla, simplemente sale con un error.
Después de todo eso vienen las cabeceras de ELF y de ejecutable PE de windows. Y dado que en Windows, por lo que se, las cabeceras de un ejecutable PE no tienen que estar al principio, le da igual.
Luego lo de que sea ejecutable en BIOS, en realidad supongo que se referirá a UEFI, porque éstas admiten ejecutables PE como los de Windows.
Creo que así es como funciona la cosa.