Если .NET работает везде, то на Windows 3.11 и DOS тоже

Автор оригинала: Scott Hanselman
  • Перевод
Я часто повторяю, что .NET Core — это опенсорс и он работает «везде». MonoGame, Unity, Apple Watch, Raspberry Pi и микроконтроллеры, дюжина линуксов, Windows и так далее. Уже немало.

Но кому-то всё-таки мало. Михал Стреховски хочет запускать C# действительно везде.


C# в Windows 3.11

Он запустил код C# в двух «невозможных» системах, которые теперь дополнили наше определение «работает везде». Хотя это забавные эксперименты (не повторяйте их в продакшне), они подчёркивают как технические способности Михала, так и гибкость базовой платформы.

Запуск C# под Windows 3.11


В семи твитах Михал рассказывает, как ему удалось запустить код C# под Windows 3.11. Приложение простое, здесь только вызов функции MessageBoxA с отображением соответствующего диалогового окна, которое в Windows с первых дней. Для вызова функции и получения результата используется DllImport/PInvoke.

Я сначала показал это приложение для Windows 3.11, потому что оно классное. Но в реальности автор начал с того места, где закончился его эксперимент с DOS. Он компилирует нативный код C#, и после этого правил больше не существует.

В этом примере он работает на платформе Win16, а не Win32. Однако в 1992 году (да, я тогда жил и программировал, и использовал это в проектах!) существовал определённый технологический мост под названием Win32s: подмножество API из Windows NT, которые были портированы обратно на Windows 3.11. Поэтому с учётом некоторых ограничений можно написать 32-битный код и обращаться из Win16 к Win32.

Михал понял, что объектные файлы, созданные AOT-компилятором CoreRT в 2020 году, можно собрать компоновщиком из Visual C++ 2.0 образца 1994 года. В результате получается машинный код, скомпонованный с интерфейсами Win32s, работающими в 16-разрядной Windows 3.11. Магия. Респект Михалу.


Простое приложение Hello World C#

Запуск C# в 8 КБ под DOS


Я и раньше писал об автономных исполняемых файлах .NET Core 3.x, я большой фанат этого дела. Моё приложение ужалось до 28 мегабайт. Это совсем немного, учитывая, что оно включает в себя среду выполнения .NET и множество других ресурсов. Конечно, не следует судить о VM/рантайме по размеру минимально возможной программы, но Михал хотел посмотреть, до какого предела можно дойти — и поставил цель 8000 байт!

Программа работает в текстовом режиме, что, по-моему, здорово. Она также устраняет необходимость в сборщике мусора, поскольку здесь отсутствует выделение ресурсов. Это означает, что вы не можете нигде использовать new. Нет ссылочных типов.

Для объявления статических массивов он использует поля fixed char []: они должны жить в стеке, а стек у нас маленький.

Конечно, когда вы пытаетесь сделать какой-то автономный экзешник .NET, то изначально получаете файл 65 мегабайт, который включает приложение, среду выполнения и стандартные библиотеки.

dotnet publish -r win-x64 -c Release

Можно применить ILLinker и PublishedTrimmed для оптимизации Tree Trimming из .NET Core 3.х, но так вы уменьшите файл лишь до 25 мегабайт.

Он попытался использовать Mono и mkbundle, доведя размер до 18,2 мегабайт, но затем поймал ошибку. И среда выполнения по-прежнему никуда не делась.

Таким образом, единственным подходящим рантаймом остался CoreRT, который не включает в себя виртуальную машину, а только вспомогательные функции.

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

Так он получил 4,7 мегабайта, но это всё равно слишком много. С некоторыми настройками можно дойти до 3 мегабайт. Можно полностью вытянуть рефлексию и дойти до 1,2 мегабайта. Теперь она поместится на дискете!

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

Этот размер в один мегабайт кажется жёстким ограничением только для .NET SDK.

Вот где Михал уходит от стандартных инструментов. Он делает реимплементацию-заглушку для базовых типов System! Затем перекомпилирует с некоторыми волшебными переключателями, чтобы вышла только IL-версия экзешника.

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

Затем передаёт это в CoreRT, чтобы получить нативный код.

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

И вот мы здесь.

«Теперь у нас zerosnake.obj — стандартный объектный файл, ничем не отличающийся от объектных файлов, создаваемых другими нативными компиляторами, такими как C или C++. Последний шаг — скомпоновать его».

Ещё несколько хитростей — и на выходе 27 КБ! Затем он убирает из компоновщика несколько переключателей, чтобы отключить и удалить различные вещи, используя те же методы, которые используют разработчики на ассемблере, и в результате остаётся 8176 байт. Эпический триллер.

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

Подпишитесь на твиттер Михала и поаплодируйте ему.
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 46

    +10

    Кайф

      –19
      А зачем?
        +16
        Потому что может.
          +13
          Наверное у человека такое хобби. Кто-то кораблики в бутылках собирает, а кто-то программирует в удовольствие.
            –9
            Я бы сказал, «занимается гинекологией в свободное время». Впрочем, кто я такой, чтобы судить, сам такой-же.
              –3
              Я бы сказал, «занимается гинекологией в свободное время». Впрочем, кто я такой, чтобы судить, сам такой-же.


              Гинекологией не гинекологией.
              А вот обнаженных девушек-моделей люблю пофотографировать в свободное от работы время.
              Хобби такое.
                +2
                Держите нас в курсе
            +2

            Вы знаете, я как-то портировал бинарный код из so библиотеки для мобильных устройств на винду и линукс (т.е. не имея исходников, держа в руках только бинарку). И не спрашивайте зачем. Просто захотелось попробовать свои силы.

              +12

              Чтобы погроммистам MS стало стыдно и они уменьшили винду в те же 8000 раз.

                –1
                Вот приняли бы закон, обязывающий производителя ОС, на каждый файл входящий в неё, писать эссе не менее чем на лист формата A4, объясняющее содержимое и предназначение этого файла.
                Вмиг бы Windows 10 в базовом варианте стала помещаться на дискету 1.44МБ, а всё остальное стало бы опциональным загружаемым через интернет.
                Сарказм конечно, но мечтательно-грустный.
                  +3
                  Вмиг бы Windows 10 в базовом варианте стала помещаться на дискету 1.44МБ, а всё остальное стало бы опциональным загружаемым через интернет больше ничего и не было бы, т.к. все время ушло на написание эссе.
                    +2
                    Вмиг бы windows 10 стало бы весить не только 30гб, но и еще 30кг многотомного описания в комплекте, который бы никто не открывал, но — положено, чтобы было.
                      0
                      Пф. Как будто сложно все либы скомпоновать в один файл.
                  –11

                  буханка_троллейбус.жпг

                    +2

                    Теперь надо подтянуть железячников и сделать одноплатный компьютер на котором 3.11 будет летать и его можно будет встраивать и можно… опять юзать старый добрый софт.

                      +1

                      Одна проблема только — безопасность. Разграничения прав же нет.

                        0

                        Ну вы-ж понимаете что безопасность тут не самое главное для энтузиастов? В той-же машине, в качестве магнитолы, или "головы" станка никак не нужны права пользователя или т.п., нужен прямой доступ к железу и готовый софт, что было у 3.11. Выводить в интернет в здравом уме такое никто не будет.
                        Лично я не отказался-бы от платы в формате rPI с 3.11, 286 процом 8 метрами оперативки и PCI слотом. Мб даже p166, 32 и AGP. Эдакий ретро мини ПК на стандартных компонентах.

                          +1
                          А потом не удивляйтесь если ваш умный дом ломанут, взломав что то типа wifi кормушки для рыбок (реальный случай).
                            +2

                            Я не буду удивляться потому что я параноик, все мои устройства сидят за микротиком за нестандартными портами, имеют очень жесткие ограничения на доступ в интернет (точней никакого) и что самое главное — они все самодельные, велосипедные и не на стандартных системах. Если их взломают и сделают что-то — я такому взломщику просто отдам свой паспорт, ключи от машины и квартиры, и перепишу на него всю собственность.


                            А мелкий компьютер на 3.11 не должен иметь выход в интернет/локалку до момент когда он необходим ему. Это не современный псевдоумный дом, который 24/7 обязан сидеть на китайских серверах и нужно обязательно поставить приложение на андроид для его работы.

                              0
                              я такому взломщику просто отдам свой паспорт, ключи от машины и квартиры, и перепишу на него всю собственность.

                              Главное теперь не спалить свой IP-адрес нигде, а то не дай бог обещание выполнять придется. :D

                                0
                                Главное теперь не спалить свой IP-адрес нигде

                                192.168.0.1 (:


                                А если серьезно — Весь IoT в локалочке разведенной физически от основного роутера двумя роутерами. Тут и машины на 98 винде и на 3.11 (ноуты) и даже хрюшка. Люблю старые игры...

                            0
                            3.11 и 286 не получится.
                              0

                              Да, вы правы. Не обратил внимания что на ноуте NodeJet у меня 486 стоит, все время думал что он 286.

                            +1

                            Ради такого можно взять "обычный" комп и написать такой же "мелкий" гипервизор для сотни-другой Win3.11.

                          +1
                          Если тот же Gimp под 3.1 не запустится, то к чему эти потуги?

                          «Ну вот, мы самолет по дорогам общего пользования пустили, только отрезали крылья и хвост, и часть крыши срезали, зато теперь самолет-вездеход.»
                            +14
                            Ви будете смеяться...

                            image

                              0
                              Восхитительно! Есть ли соус?
                                0

                                Вы об этом?

                                  0
                                  таки да!
                                  +1
                                  «Соус, анончик»! Арго двача на хабре, прекрасно, прекрасно!
                                  +1
                                  Таки, разговор о том, что не полетит.
                                  0
                                  Ви будете смеяться...
                                  Отчего же?


                                  «К сокровищам авиакатастрофы» ,1981
                                +10
                                Ждём запуска на z80
                                  +4
                                  Я часто повторяю, что .NET Core — это опенсорс и он работает «везде». MonoGame, Unity, Apple Watch, Raspberry Pi и микроконтроллеры, дюжина линуксов, Windows и так далее. Уже немало.

                                  А разве это верное утверждение? Все-таки Unity и Xamarin ездят на Mono. Пока. Хотя я могу ошибаться. Вот когда выпустят .NET 5, в который войдут куски и .NET Core, и Mono, наверное тогда можно будет говорить, что .NET работает везде.

                                    +2
                                    Моё приложение ужалось до 28 мегабайт. Это совсем немного

                                    DOS 6.22 + Windows 3.11 + Word 6.0 + Excel 5.0 + 1C 6.0.
                                    "Косынка" в комплекте.
                                    Куда еще 8 метров девать пока не понятно… На прон секстрис разве что.

                                      0
                                      Добавить компилятор C++ и еще 1Mb останется
                                      +2

                                      Sega megadrive?

                                        +3
                                        Чем-то неуловимо напоминает то, как я лет 15 назад писал виндовые ядерные драйверы на Delphi
                                          0
                                          Win32s: подмножество API из Windows NT… обращаться из Win16 к Win32

                                          Ровно наооборот — из Win32 к Win16, подсистема Win32s нативно загружает Win32 exe и dll, и исполняет 32-х разрядный код. Для вызова 16-битного кода там есть (был, если точнее) специальный гейт.
                                            0
                                            Круто
                                              +1

                                              Но ведь Unity использует Mono, а не .NET Core

                                                0
                                                Теперь ждём порт на DOS4GW / cwsdpmi — 32 бита адресуемой памяти, защищённый режим…
                                                  0
                                                  Друзья, я правильно понимаю, что при использовании такой связки инструментов производится компиляция в нативный код самой программы и библиотек (которые усечены) с целью запуска на некоей целевой платформе? Как при таком технологическом процессе обстоят дела со сборщиком мусора? Я понимаю, что автор исключил это для исключения RTL, но если задаться целью сохранить — будет в целевом коде GC или это только при работе виртуальной машины есть? Спасибо.

                                                  P.S. знает ли кто-то стоящие интереса самописные net рантаймы? Не MS, пусть и opensource, а отдельные? Пусть упрощенные, без JIT.
                                                  0
                                                  Автор указал в начале статьи, что NET Core можно запустить на микроконтроллерах. Этот момент очень интересен…
                                                  Прям вот очень)
                                                  Знает кто-нибудь об этом что-нибудь?

                                                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                  Самое читаемое