- PVSM.RU - https://www.pvsm.ru -

Зачем нужен эмулятор retrowin32

Зачем нужен эмулятор retrowin32 - 1

Самый популярный вопрос о моём эмуляторе Windows retrowin32 [1] (после «Зачем вообще это нужно?») — это вопрос о том, как он работает. Сегодня ответ кажется мне очевидным, но прежде чем я разобрался, он представлял для меня огромную загадку. Поэтому я постараюсь объяснить так, чтобы вам тоже стало понятно.

Эмуляция Windows API

Для начала представьте, что вы работаете с машиной x86, на которой установлена какая-то операционная система (не Windows), и вам нужно как-то запустить программу для Windows. Основной вывод из наблюдения за Wine (который, как следует из расшифровки аббревиатуры Wine Is Not Emulator, не является эмулятором) заключается в том, что исполняемый файл Windows в конечном итоге содержит последовательность команд x86, а ваша машина x86 уже способна напрямую исполнять их. Значит, для исполнения файла .exe Windows вам достаточно просто загрузить его в память (для чего нужно распаковать формат файлов .exe) и приказать процессору перейти к первой команде.

Единственное, что остаётся (и это очень масштабная задача) — способ взаимодействия этого exe с операционной системой, например, как он открывает файлы или выводит что-то на экран. Механизм сильно отличается для разных операционных систем, но в конечном итоге зависит от интерфейса ядра. В конкретном случае Windows интерфейс ядра довольно замороченный (идентификаторы системных вызовов различаются для разных версий Windows [2]), и обычно считается, что стабильная граница API находится в DLL со знакомыми вам именами наподобие kernel32.dll. (Это является полной противоположностью Linux, который известен своим вниманием [3] к наличию очень стабильного интерфейса на границе ядра.)

Это работает следующим образом: формат файлов .exe может объявить: «эй, мне нужно будет вызвать функцию kernel32.dll с именем WriteFile()», и когда .exe загружается, операционная система помещает соответствующий код в соответствующее место так, чтобы вызов функции сработал. Затем в Windows функция kernel32 вызывает соответствующий интерфейс ядра. Это удобно для выполнения нашей цели запуска файла в ОС, отличной от Windows, потому что нам достаточно лишь предоставить собственные реализации этих функций, даже не обращая внимания на интерфейс ядра.

Именно так и поступает Wine: он загружает файлы .exe и предоставляет реализации всех DLL Windows. Естественно, на практике всё существенно сложнее, и Wine потребовались века человеко-часов работы программистов, чтобы воспроизвести все особенности и странности интерфейса Windows, который сам десятки лет подвергался воздействию закона Хайрама [4].

Один из примеров того, насколько глубока может быть кроличья нора, можно увидеть в этом фрагменте [5], находящемся в блобе ассемблерного кода x86 диспетчера системных вызовов Wine:

/* Legends of Runeterra подменяет первую команду возврата системного вызова,
 * и ожидает, что туда перейдёт выполнение. Изменяем адрес возврата соответствующим образом. */
"subq $0xb,0x70(%rcx)nt"

В отличной статье how Wine works [6] ещё подробнее рассказывается о Wine. Я намеренно опустил множество деталей.

(Кстати, у Wine есть один интересный способ применения, никак не связанный с задачей этого поста — если у вас есть исходный код программы для Windows, то можно скомпилировать его для созданной в Wine реализации Windows API [7] и получить на выходе нативный исполняемый файл.)

Эмуляция x86

Всё описанное выше отлично работает на оборудовании x86, но что если вы на какой-то другой архитектуре, например, на новых Mac с процессорами ARM? Тогда вам нужно эмулировать набор команд x86 точно так же, как эмулятор Game Boy может эмулировать процессор Game Boy.

А это непростая задача! Apple даже добавила в свои процессоры ARM специальную поддержку x86 [8], чтобы ускорить эмуляцию. Но после того, как вы справитесь, то дальше можете пойти по двум разным путям.

Первый: дополнительно эмулировать всё оборудование, находящееся в машине x86, например, BIOS и интерфейсы дисков, так, чтобы можно было установить в ваш эмулятор настоящую ОС Windows. Этот подход используется в qemu [9]. Есть также веб-эмулятор v86 [10], способный запускать множество разных ОС, в том числе и Windows.

Такой подход прекрасен тем, что запускается настоящая копия Windows; следовательно, все программы для Windows будут работать корректно. Основной недостаток этого подхода в том, что необходимо устанавливать реальную копию Windows, что требует много пространства на диске и времени на запуск Windows, прежде чем приступать к исполнению программ.

Второй подход: эмулировать набор команд x86 и использовать описанный выше Wine в качестве реализации огромного Windows API, основывающегося на чём-то более удобном для эмуляции, например, на API ядра Linux. После публикации retrowin32 я узнал о BoxedWine [11], который выполняет эту задачу в вебе и способен запускать множество сложных программ для Windows.

Подход retrowin32

Мой проект retrowin32 в основном предназначен для изучения того, что мне кажется интересным. На текущий момент это значит, что у меня есть не особо хороший эмулятор x86, не особо хорошая реализация win32 и исследовано несколько близких по теме задач.

В целом, я думаю, что если вам хочется запустить программу для Windows в вебе, то, скорее всего, лучше всего подойдут BoxedWine и v86. Но если вам любопытны мои исследования, то ждите следующего поста, в котором я напишу о текущем состоянии retrowin32.

Автор:
PatientZero

Источник [12]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/staroe-zhelezo/382325

Ссылки в тексте:

[1] retrowin32: https://neugierig.org/software/blog/2022/10/retrowin32.html

[2] идентификаторы системных вызовов различаются для разных версий Windows: https://j00ru.vexillium.org/syscalls/nt/64/

[3] своим вниманием: https://lkml.org/lkml/2012/12/23/75

[4] закона Хайрама: https://www.hyrumslaw.com/

[5] этом фрагменте: https://github.com/wine-mirror/wine/blob/a8c1d5c108fc57e4d78e9db126f395c89083a83d/dlls/ntdll/unix/signal_x86_64.c#L2647

[6] how Wine works: https://werat.dev/blog/how-wine-works-101/

[7] скомпилировать его для созданной в Wine реализации Windows API: https://wiki.winehq.org/Winelib_User%27s_Guide

[8] специальную поддержку x86: https://twitter.com/ErrataRob/status/1331735383193903104

[9] qemu: https://www.qemu.org/

[10] v86: https://copy.sh/v86/

[11] BoxedWine: http://www.boxedwine.org/

[12] Источник: https://habr.com/ru/post/712454/?utm_source=habrahabr&utm_medium=rss&utm_campaign=712454