Hace 2 años | Por --625430-- a justine.lol
Publicado hace 2 años por --625430-- a justine.lol

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.

Comentarios

D

#25 creo que la cosa funciona así:

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.

t

#9 Pues si quieres y puedes explicalo porque al desarrollador en su página se le da fatal...

https://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...

t

#9 #9 Pues si quieres y puedes explicalo porque al desarrollador en su página se le da fatal...

https://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?

D

#8 He probado con un binario estático en Go (amfora, cliente Gemini) y como era de esperar ha cascado con el runtime de Go.

Eso con tinyemu.com. Aún así es asombroso.

D

#4 He probado en DOSBox y OpenBSD el mismo binario y parece que va.

c

#10 Claro, misma arquitectura.

D

#12 No del todo.

c

#13 Hombre, si.

Prueba a ejecutarlo en un ARM a ver, aunque sea el mismo S.O.

dqenk

Esto parece demasiado bonito para ser verdad. Y me parece raro raro que libc no tenga el mejor memcpy() que sea posible escribir.

c

#1 Eso parece una magufada en toda regla.
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...

Find

#1 "compila una vez y abre donde sea" es el "chupa que yo te aviso" del software

mudit0

¿Como Visual Basic 5, que iba a hacer ejecutables nativos sin necesidad de runtimes ni de bibliotecas adicionales?

D

#6 Más bien Golang, creo que VB5 tenía una DLL no?

mudit0

#15 Bueno, en realidad tenía más de 1 porque con sólo esa era difícil hacer cosas más allá de una calculadora o un Hola Mundo.

D

Cosmopolitan C, el C para la mujer moderna de hoy

D

#18 Lee la sección "x86-64 Linux ABI Makes a Pretty Good Lingua Franca" en https://justine.lol/ape.html

c

#27 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

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.

D

#28 Todo eso lo se, y precisamente esa es la función de la biblioteca esta, aparte de ofrecer una stdlib ligera: abstraer la parte de E/S.

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.

D

#28 Creo que ya se cómo funciona. Lo comento en #_25

c

#23 Ok.
Misterio resuelto.
Muchas gracias.

D

Me da pereza volver a C vista la velocidad de desarrollo de Python.

saqueador

#17 Hombre, si dijeras rust, vale. Pero python y C no juegan en la misma liga. Es que ni siquiera juegan el mismo deporte.

D

#22 No entiendo cómo tu respuesta se relaciona con mi comentario.

D

#17 C se usa para hacer programas de sistema y juegos como Python

D

#33 python es un juego?

D

¿Pero esto qué es exactamente? ¿Una biblioteca libc que se enlaza estáticamente? ¿Y eso no se puede hacer con la libc de GNU?

D

#5 Sí, es más o menos lo que estaba viendo, pero no acabo de ver cómo consigue que funcione el cargador en sí.

c

#7 La única diferencia entre un SO y otro es la estructura del ejecutable. Si envuelves el ejecutable de un código que le de compatibilidad ya está.

El código máquina no tiene que ver con el SO, es común.

D

#19 No, si eso lo se. Lo que intento desentrañar es cómo funciona esa "envoltura" capaz de funcionar como un ejecutable PE de windows, de DOS y lanzarse directamente en un sistema UNIX.

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?

c

#5 Viene a ser un bytecode de Java, pero sin JVM.


Francamente, no le veo ni remotamente el parecido con una JVM de Java.

h

RISC-V ven ya, ven pronto...