Si .NET funciona en todas partes, tambi茅n en Windows 3.11 y DOS

A menudo repito que .NET Core es de c贸digo abierto y funciona "en todas partes". MonoGame, Unity, Apple Watch, Raspberry Pi y microcontroladores, una docena de Linux, Windows, etc. Ya mucho

Pero alguien todav铆a no es suficiente. Michal Strehowski quiere lanzar C # realmente en todas partes .


C # en Windows 3.11

Ejecut贸 el c贸digo C # en dos sistemas "imposibles" que ahora complementan nuestra definici贸n de "funciona en todas partes". Aunque estos son experimentos divertidos (no los repita en producci贸n), enfatizan tanto las habilidades t茅cnicas de Michal como la flexibilidad de la plataforma base.

Ejecutando C # en Windows 3.11


En siete tweets, Michal habla sobre c贸mo logr贸 ejecutar el c贸digo C # en Windows 3.11. La aplicaci贸n es simple, solo hay una llamada a la funci贸n MessageBoxA con la visualizaci贸n del cuadro de di谩logo correspondiente, que est谩 en Windows desde los primeros d铆as. Para llamar a la funci贸n y obtener el resultado , se utiliza DllImport / PInvoke.

Primero mostr茅 esta aplicaci贸n para Windows 3.11 porque es genial. Pero en realidad, el autor comenz贸 desde el lugar donde termin贸 su experimento con DOS. Compila el c贸digo nativo de C #, y despu茅s de eso las reglas ya no existen.

En este ejemplo, se ejecuta en la plataforma Win16, no en Win32. Sin embargo, en 1992 (s铆, 隆viv铆 y program茅, y lo us茅 en mis proyectos!) Hubo un cierto puente tecnol贸gico llamado Win32s : un subconjunto de las API de Windows NT que se transfirieron a Windows 3.11. Por lo tanto, teniendo en cuenta algunas restricciones, puede escribir c贸digo de 32 bits y acceder a Win32 desde Win16.

Michal se dio cuenta de que los archivos de objetos creados por el compilador CoreRT AOT en 2020 pod铆an ser ensamblados por el vinculador de la muestra de Visual C ++ 2.0 de 1994. El resultado es un c贸digo de m谩quina vinculado con interfaces Win32s que se ejecutan en Windows 3.11 de 16 bits. La magia Respeta a Michalu.


Aplicaci贸n simple Hello World C #

Ejecutando C # a 8K bajo DOS


He escrito sobre ejecutables independientes de .NET Core 3.x antes, soy un gran admirador de esto. Mi aplicaci贸n ya se ha reducido a 28 megabytes. Esto es bastante, dado que incluye el tiempo de ejecuci贸n de .NET y muchos otros recursos. Por supuesto, uno no debe juzgar VM / runtime por el tama帽o del programa m谩s peque帽o posible, pero Michal quer铆a ver hasta qu茅 l铆mite puede ir, 隆y establecer un objetivo de 8000 bytes!

El programa funciona en modo texto, lo cual, en mi opini贸n, es genial . Tambi茅n elimina la necesidad de un recolector de basura, ya que no hay asignaci贸n de recursos. Esto significa que no puede usar nuevo en ning煤n lado. No hay tipos de referencia.

Para declarar matrices est谩ticas, utiliza campos fixed char [] : deben vivir en la pila, y tenemos una peque帽a pila.

Por supuesto, cuando intenta hacer alg煤n tipo de .NET independiente ejecutable, inicialmente obtiene un archivo de 65 megabytes, que incluye la aplicaci贸n, el tiempo de ejecuci贸n y las bibliotecas est谩ndar.

dotnet publish -r win-x64 -c Release

Puede usar ILLinker y PublishedTrimmed para optimizar Tree Trimming desde .NET Core 3.x, pero de esta manera reduce el archivo a solo 25 megabytes.

Intent贸 usar Mono y mkbundle, elevando el tama帽o a 18.2 megabytes, pero luego detect贸 un error. Y el tiempo de ejecuci贸n sigue ah铆.

Por lo tanto, el 煤nico tiempo de ejecuci贸n adecuado era CoreRT, que no incluye una m谩quina virtual, sino solo funciones auxiliares.

dotnet publish -r win-x64 -c Release /p:Mode=CoreRT

Entonces obtuvo 4,7 megabytes, pero a煤n es demasiado. Con algunas configuraciones, puede caminar hasta 3 megabytes. Puede extender completamente la reflexi贸n y alcanzar 1.2 megabytes. 隆Ahora cabe en un disquete!

dotnet publish -r win-x64 -c Release /p:Mode=CoreRT-ReflectionFree

Este tama帽o de un megabyte parece un l铆mite estricto solo para el SDK de .NET.

Aqu铆 es donde Michal se aleja de las herramientas est谩ndar . 隆Hace un trozo de reimplementaci贸n para los tipos b谩sicos de Sistema ! Luego se vuelve a compilar con algunos interruptores m谩gicos para que solo se publique la versi贸n IL del ejecutable.

csc.exe /debug /O /noconfig /nostdlib /runtimemetadataversion:v4.0.30319 MiniBCL.cs Game\FrameBuffer.cs Game\Random.cs Game\Game.cs Game\Snake.cs Pal\Thread.Windows.cs Pal\Environment.Windows.cs Pal\Console.Windows.cs /out:zerosnake.ilexe /langversion:latest /unsafe

Luego pasa esto a CoreRT para obtener el c贸digo nativo.

ilc.exe zerosnake.ilexe -o zerosnake.obj --systemmodule zerosnake --Os -g

Y aqui estamos.

鈥淎hora tenemos zerosnake.obj, un archivo de objetos est谩ndar, no diferente de los archivos de objetos creados por otros compiladores nativos, como C o C ++. El 煤ltimo paso es armarlo ".

Unos cuantos trucos m谩s, 隆y la salida es de 27 KB! Luego, elimina varios modificadores del enlazador para deshabilitar y eliminar varias cosas usando los mismos m茅todos que usan los desarrolladores del ensamblador, lo que resulta en 8176 bytes. Thriller 茅pico.

link.exe /debug:full /subsystem:console zerosnake.obj /entry:__managed__Main kernel32.lib ucrt.lib /merge:.modules=.rdata /merge:.pdata=.rdata /incremental:no /DYNAMICBASE:NO /filealign:16 /align:16

Sigue a Michal en Twitter y aplaudenlo.

Source: https://habr.com/ru/post/485268/


All Articles