Перейти к содержимому

Как запускать программы для windows на linux

  • автор:

Wine — запуск Windows-программ в Linux без виртуальных машин

Несмотря на унификацию интерфейсов современных операционных систем, переход с Windows на Linux может оказаться достаточно болезненным. Многих смущает то обстоятельство, что они более не смогут пользоваться своими любимыми и столь привычными приложениями, ведь далеко не весь популярный софт является кроссплатформенным. На самом деле не всё так уже и безнадежно.

Для Linux-систем существует программное обеспечение, позволяющее запускать исполняемые EXE -файлы так же, как в среде Windows.

Называется оно Wine, что в вольном переводе звучит как «винишко». Когда вы запускаете в Linux исполняемый EXE -файл, Wine подменяет вызовы библиотек Windows на системные вызовы Linux, благодаря чему пользователи могут полноценно работать с Windows-приложениями и играми практически без потери производительности. Иначе говоря, Wine эмулирует среду Windows, создавая нечто вроде промежуточного слоя между Linux и Windows и обеспечивая тем самым доступ win-приложениям к файловой системе Linux.

Установка Wine

Рассмотрим установку и работу с Wine на примере с Ubuntu .

Чтобы установить Wine, откройте терминал и выполните команду sudo apt install wine-stable с подтверждением загрузки пакетов.

Apt install wine

Процедура скачивания и установки может занять несколько минут, так что наберитесь терпения.

Терминал

Для установки мы использовали последнюю стабильную версию 3.0.

Установка Windows-программ в Linux

Установим с помощью Wine в Linux какую-нибудь виндовую программу, например, текстовый редактор Notepad++.

Переходим в папку с исполняемым exe -файлом, открываем текущее расположение в терминале через контекстное меню.

Контекстное меню

И выполняем простую команду wine AtomSetup.exe .

Wine

Возможно, при первом запуске Wine предложит установить дополнительные компоненты вроде Net Framework , обязательно устанавливаем.

Установка

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

Npp

Примечание: несмотря на то, что Wine постоянно совершенствуется, остается еще немало приложений Windows, которые могут работать в эмулируемой среде некорректно.

Если у вас возникнут затруднения с запуском win-приложений, воспользуйтесь программой q4wine, представляющей собой удобную графическую оболочку для Wine.

Q4wine

Допустим, вы установили win-программу, но не можете ее найти среди других установленных программ.

Откройте q4wine, нажмите Ctrl + Z и кликните по иконке обзора в поле «Программа».

Q4wine

Откроется окно «Открыть EXE-файл» как раз в расположении папки префикса .wine , содержащей эмулируемую windows-структуру каталогов drive_c/Program Files .

Q4wine

Выбрав исполняемый exe -файл нужной вам программы, нажмите в окне q4wine «OK».

Q4wine

И win-приложение будет запущено.

Как в Linux запустить программу для Windows

Как в Linux запустить программу для Windows

Поскольку вы находитесь здесь, я предположу, что вы пользователь Linux. И время от времени вы задаетесь вопросом: могу ли я запускать приложения windows в Linux?

Ответ на этот вопрос — да, вы можете запускать приложения Windows в Linux. Вот некоторые способы запуска программ Windows в Linux:

  • Установка Windows на отдельный раздел жесткого диска
  • Установка Windows в качестве виртуальной машины в Linux

Оба они работают просто отлично. Но они несколько требовательны к ресурсам.

Если вам нужно использовать только небольшое приложение Windows, установка Windows на отдельный раздел жесткого диска или в качестве виртуальной машины неэффективна. Более того, виртуальная машина не может использовать всю мощность вашей машины. Итак, каково же решение?

Не волнуйтесь, есть другой способ использовать программное обеспечение Windows в Linux. Он называется Wine. Если вы еще не знакомы с ним или являетесь новичком в мире Linux, эта статья для вас.

В этом руководстве для начинающих я покажу вам, что такое Wine и как использовать его для запуска программ Windows в Linux. Я использовал здесь Ubuntu, поскольку Ubuntu является одним из лучших дистрибутивов Linux для начинающих, но любой другой дистрибутив Linux будет иметь более или менее те же шаги (за исключением команд в дистрибутивах на базе Arch или Fedora).

Использование Wine для запуска программ Windows в Linux

Wine означает Wine Is Not an Emulator. И WINE на самом деле является акронимом этого слова. И, как уже говорилось ранее, это даже не виртуальная машина.

Скорее это уровень совместимости для запуска приложений Windows на UNIX-подобных или POSIX-совместимых операционных системах (например, Linux, Mac, BSD). В то время как виртуальная машина или эмулятор имитирует внутреннюю логику Windows, Wine переводит эту логику Windows в родную логику UNIX/POSIX-совместимости.

Говоря простыми и нетехническими терминами, Wine преобразует внутренние команды Windows в команды, которые ваша Linux-система может понимать как родные.

Установка Wine

Существуют различные способы установки Wine на вашу систему. Поскольку это руководство для начинающих, я опишу самый простой из них.

Почти все дистрибутивы Linux поставляются с Wine в репозитории пакетов. Чаще всего в репозитории пакетов доступна последняя стабильная версия Wine. Установить Wine на Ubuntu так же просто, как открыть терминал и выполнить следующие команды:

sudo apt update sudo apt install wine

Однако если вы используете 64-разрядную установку Ubuntu, вам потребуется выполнить эти дополнительные команды:

sudo dpkg --add-architecture i386

Это добавит поддержку 32-разрядной архитектуры в ваш дистрибутив, что поможет вам при установке определенного программного обеспечения.

Какие приложения Windows поддерживаются Wine?

Существует большое количество приложений Windows, которые в настоящее время полностью поддерживаются Wine. Они будут работать без каких-либо проблем.

Однако каждый день разрабатываются новые приложения Windows. Многие из них не будут работать в Wine так, как мы хотим. Но темпы развития Wine также стремительны, поддержка новых приложений добавляется постоянно.

И для отслеживания этого существует специальная база данных.

База данных приложений Wine содержит почти 24 000 приложений, имеющих различные статусы в зависимости от того, насколько хорошо эти приложения работают в Wine. Если вы хотите быстро проверить рейтинг приложения, которое вы хотите использовать в Wine, вы можете заглянуть туда. Вот значение этих рейтингов:

  • Platinum: Эти приложения устанавливаются и безупречно работают в «готовом» Wine.
  • Gold: Эти приложения работают безупречно с некоторыми специальными настройками.
  • Silver: Приложения с незначительными проблемами помечаются как Silver.
  • Bronze: Бронзовые имеют серьезные проблемы, которые достаточно сильно влияют на использование.
  • Garbage: Они просто не будут работать в Wine.

Отзывы, процедура установки, с какой версией Wine оно тестировалось и различные полезные данные также доступны для каждого приложения здесь.

Разумеется, база данных приложений Wine — это в основном пользовательские данные, поэтому вы всегда можете попробовать запустить приложение с другой версией Wine и поделиться своими результатами с остальными членами сообщества.

Поиск приложения в базе данных приложений Wine

Давайте посмотрим, как мы можем найти приложение в базе данных приложений Wine.

Перейдите в раздел База данных приложений Wine. Нажмите кнопку Browse Apps (Обзор приложений) на левой боковой панели.

Finding an App in Wine AppDB

Напишите имя приложения, которое вы хотите найти, в поле Имя.

Wine AppDB name filter

Нажмите на ссылку-приложение из результата поиска.

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

Wine AppDB Application page

Давайте нажмем на ссылку «Последняя версия».

Это главная страница, которую вам нужно проверить. Там будет подробная информация об этой конкретной версии.

Detailed Information about Application

Вы получите представление о том, что будет работать, а что нет. Также здесь будет приведена процедура установки, если для установки потребуются какие-либо дополнительные задачи.

Начало работы с Wine

Прежде чем приступить к установке и запуску приложений в Wine, мы должны иметь четкое представление о некоторых вещах и о том, как настроить Wine для использования:

WinePrefix

Приложениям Windows необходим диск C:. Wine использует для этой цели виртуальный диск C:. Каталог этого виртуального диска C: называется wineprefix. Прежде всего, нам нужно создать wineprefix. Для этого откройте терминал и введите следующую команду:

winecfg

Это создаст wineprefix и откроет окно конфигурации для Wine. Вы можете изменить параметры конфигурации, если хотите, или оставить все как есть и закрыть его. Теперь вы можете найти виртуальный диск C: по адресу

$HOME/.wine/c_drive

WinePrefix C: Drive

Общее правило — устанавливать каждое новое приложение в новый wineprefix. Мы можем создавать и поддерживать несколько wineprefix вручную. Но эта задача покажется довольно утомительной для новичков. Поэтому мы пока пропустим эту часть. Но позже я покажу, как можно легко выполнить эту часть.

Установка приложения с помощью Wine

Установка поддерживаемого приложения в Wine обычно не сложнее двойного щелчка по установочному файлу. Однако сейчас мы рассмотрим пошаговое руководство по установке 7-zip в Wine.

Прежде всего, проверьте рейтинг 7-zip в базе данных приложений Wine. Он имеет рейтинг Platinum, так что все готово. Откройте конфигурацию Wine ( winecfg ) и установите версию Windows на Windows 7.

Wine Windows 7

Щелкните правой кнопкой мыши на установочном файле 7-zip и выберите Open With Wine Windows Program Loader.

7-zip Installation File

Видите путь к конечной папке? Установка 7-zip распознала виртуальный диск C: из wineprefix.

7zip Setup Directory on Wine

Завершите установку и перейдите в каталог установки [ $HOME/.wine/drive_c/Program Files/7-zip/ ] из браузера файлов.

Щелкните правой кнопкой мыши на файле 7zFM.exe и выберите Свойства > Открыть с помощью.

Set Default .exe Loader

Выберите Wine Windows Program Loader и закройте окно. Дважды щелкните на файле 7zFM.exe.

7-zip running with Wine

И вот, пожалуйста! Для создания ярлыка на рабочем столе щелкните правой кнопкой мыши на файле.

Creating 7-zip shortcut

Теперь переместите ссылку на рабочий стол.

Move shortcut to Desktop

Теперь вы можете запускать 7-zip просто с рабочего стола. Все, что вам нужно сделать, это дважды щелкнуть по значку.

Run 7zip from desktop

Если вы хотите получить доступ к своим файлам в Linux, они обычно находятся на диске Z:.

Linux directory in Z: drive

Вы можете использовать 7-zip так же, как и в Windows — для извлечения и создания архивов и тому подобного.

Давайте сделаем все (намного) проще

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

Это связано с быстрыми темпами развития Wine. Хотя приложение работает с текущей версией Wine, оно может не работать с будущей версией из-за внесенных изменений.

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

На помощь приходит PlayOnLinux. Он предоставляет удобный интерфейс для выполнения всех этих действий. Для установки PlayOnLinux на Ubuntu просто выполните эту команду:

sudo apt install playonlinux

PlayOnLinux interface

С помощью PlayOnLinux вы можете легко выполнить любую задачу, связанную с Wine, используя красивый и интуитивно понятный графический интерфейс:

  • Установка и удаление приложений.
  • Создание, обновление и удаление wineprefixes.
  • Поддерживать Wine различных архитектур и версий.
  • Запуск и создание ярлыков для установленных приложений.
  • И так далее.

Но все же вам нужно будет проверить базу данных приложений Wine на предмет отзывов, процедур установки и тому подобного.

Преимущества использования Wine

Когда речь идет о запуске приложений Windows в системе Linux, Wine предоставляет множество преимуществ по сравнению с использованием эмуляторов или виртуальных машин.

  • Производительность: Wine не подвержен снижению производительности, которое в противном случае происходит при эмуляции.
  • Нативный опыт: Нет необходимости открывать Wine перед запуском приложения Windows. Как именно работает Wine, станет более понятно из этой цитаты с официального сайта,

Wine можно рассматривать как эмулятор Windows примерно так же, как Windows Vista можно рассматривать как эмулятор Windows XP: оба позволяют запускать одни и те же приложения, переводя системные вызовы примерно одинаковым образом. Настройка Wine для имитации Windows XP мало чем отличается от настройки Vista для запуска приложения в режиме совместимости с XP.

Производные Wine

Существует довольно много проектов для запуска приложений Windows на других платформах, основанных на Wine:

  • CrossOver: CrossOver разработан компанией CodeWeavers. Она основана непосредственно на Wine с некоторыми изменениями и собственными дополнениями. На самом деле, в CodeWeavers работает большая часть разработчиков Wine. В отличие от быстрых релизов Wine, релизы CrossOver более стабильны. Единственным и основным недостатком является то, что Crossover не является бесплатным.
  • PlayOnLinux: PlayOnLinux полностью основан на Wine. Он обеспечивает более легкий путь для установки и управления приложениями с помощью Wine. PlayOnLinux бесплатен. Он также доступен для Mac как PlayOnMac.
  • ReactOS: ReactOS — это совершенно другая операционная система с открытым исходным кодом для запуска приложений Windows. В ней повторно используется значительное количество кода из Wine. Однако этот проект находится в разработке уже более десяти лет, и я не стал бы его рекомендовать.

Дополнительные советы по использованию Wine

Winetricks

Это еще одна важная часть использования Wine. Winetricks — это вспомогательный скрипт для загрузки и установки различных перераспределяемых библиотек времени выполнения, необходимых для запуска некоторых приложений в Wine. Они могут включать замену компонентов Wine, использующих библиотеки с закрытым исходным кодом. Winetricks поставляется вместе с установкой Wine на Ubuntu.

Для запуска winetricks выполните эту команду:

winetricks 

Winetricks

Существует множество вариантов помощи в решении различных задач.

Установка приложения с помощью Winetricks

Если вы установите приложение из winetricks, оно будет установлено в отдельный wineprefix. Давайте установим VLC:

Winetricks - Install an appWinetricks - Install VLC

После этого начнется загрузка установочных файлов VLC. А затем проведет вас через весь остальной процесс. Это довольно просто.

Установка DLL или компонентов Windows и другое

Вы можете выбрать wineprefix из winetricks и установить различные библиотеки и компоненты, необходимые для запуска приложения, а также выполнить другие операции.

Winetricks ScriptsWinetricks Libraries & Components

Примечание: Если использование winetricks кажется вам сложным, это совершенно нормально. Я тоже так считаю. По этой причине я всегда использую PlayOnLinux. PlayOnLinux может делать все, что вам может понадобиться от winetricks.

Для получения дополнительной информации вы можете ознакомиться с FAQ и документацией по Wine.

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

Сообщите нам, если у вас есть вопросы или мнения, в разделе комментариев ниже.

Как запустить Windows-приложение в Linux?

Всем привет! Практически у всех начинающих пользователей Linux, которые только перешли с Windows, возникает один и тот же вопрос – а как в Linux запустить программу (игру), которая была в Windows? Иными словами, как запустить программу или игру, которая была разработана для Windows, в Linux, т.е. в другой операционной системе. В этом материале я расскажу Вам, можно ли это сделать, и если можно, то как.

Как запустить Windows-приложение в Linux

Можно ли запустить Windows-приложение в Linux?

Для начала обязательно отмечу, что Linux – это совсем другая платформа, не Windows и не совместимая с ней, поэтому абсолютно любая программа или игра, разработанная для Windows, запускается только на Windows.

На заметку! Новичкам рекомендую почитать мою книгу «Linux для обычных пользователей» – в ней я подробно рассказываю про основы операционной системы Linux, и как пользоваться этой системой без командной строки.

Однако, так как эти вопросы задаются, и возник спрос, существует возможность запускать Windows-приложения в Linux, но это не стандартная возможность, которая не гарантирует нормального функционирования программы, да и не все программы так можно запустить, а еще к тому же, за счет того, что запускаются именно Windows-приложения, значительно снижается безопасность системы. Поэтому лучше не использовать возможность, которую я опишу чуть ниже, а пользоваться стабильными приложениями, разработанными именно для Linux.

Обзор инструментов Wine, Winetricks и PlayOnLinux

Итак, если у Вас все-таки остро стоит задача запустить Windows-кую программу в Linux, то существует специальная программа под названием Wine.

Скриншот 1

Wine – это альтернативная реализация Windows API.

Иными словами, Wine создает условия для запуска Windows-программ в Linux. При этом Wine – это не эмулятор, т.е. это не виртуальная машина, она не эмулирует оборудование, не эмулирует операционную систему, как я уже отметил, она является альтернативной реализацией Windows API, что и позволяет запускать Windows-программы в Linux.

Но как я уже отметил, совместимость программ не полная, не все программы поддерживаются, а те, которые поддерживаются, могут работать некорректно. В то же время большинство популярных программ работают в Wine очень даже неплохо, например, есть возможность запустить даже Microsoft Office.

Для упрощения установки и запуска Windows-программ в Linux разработчики также придумали специальные вспомогательные инструменты, которые упрощают всю эту работы.

К таким инструментам относится скрипт Winetricks.

Winetricks – скрипт для загрузки и установки различных распространённых библиотек, необходимых для запуска некоторых программ в Wine. Winetricks автоматически создаёт для программ правильные настройки и скачивает требуемые для их работы компоненты.

Winetricks – скрипт для упрощения работы с Wine.

Еще одним инструментом для упрощения установки Windows-приложений в Wine является программа – PlayOnLinux. Она создана для автоматизации установки программ и игр, созданных для Windows в Linux, т.е. она может автоматически скачать и установить некоторые программы (игры). Также PlayOnLinux в случае необходимости может скачать специальную версию Wine вместе с настройками для конкретной программы, и даже применять к программе некоторые исправления для того, чтобы добиться более стабильной работы.

PlayOnLinux – графическая программа, надстройка над Wine, которая упрощает установку и использование программ и игр в Linux, которые были разработаны для Windows.

Скриншот 2

По факту PlayOnLinux – это что-то вроде менеджера программ с графическим интерфейсом, в котором уже по умолчанию отображаются программы, которые можно установить, т.е. Вы просто выбираете программу и запускаете установку. И тем самым по сути, если программа есть в списке PlayOnLinux, то Вы сможете установить ее и запустить в Linux, для этого выполнив всего несколько простых шагов мастера.

Однако работа с PlayOnLinux и, в частности, с Wine непредсказуемая, иными словами, стандартного сценария установки программ нет, в процессе установки любой программы могут (и, наверное, будут) появляться различные ошибки, например, отсутствие какого-нибудь пакета или еще что-нибудь.

Поэтому установка Windows-приложений в Linux — это дело индивидуальное, и рассчитывать на стандартный способ установки не приходится. А лучше вообще использовать приложения на той платформе, для которой они были разработаны, т.е. Windows-приложения на Windows, а Linux-программы на Linux.

Но, как говорится, если Вы не ищете легких путей, то можете установить Wine или PlayOnLinux, и пробовать устанавливать различные Windows-приложения.

Установка и запуск Windows-приложения в Linux

Теперь давайте я покажу, как установить и запустить Windows-приложение в операционной системе Linux, в качестве примера я возьму программу Notepad++, которая была разработана для Windows, т.е. версии для Linux на текущий момент у этой программы нет.

Шаг 1 – Установка Wine

Сначала необходимо установить программу Wine. Пример установки Wine можете посмотреть в материале – Установка Wine в Linux Mint, в этой статье я подробно рассказывал и показывал, как установить Wine в дистрибутиве Linux Mint.

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

Шаг 2 – Скачивание установочного файла программы

Следующее, что нужно сделать, это, конечно же, скачать установочный дистрибутив программы, в нашем случае Notepad++, т.е. так же, как и в Windows, Вам необходимо скачать ровно тот же самый установочный файл, который Вы бы использовали, если устанавливали программу на Windows.

Шаг 3 – Установка программы

После того как Вы установили Wine, Вы можете запускать exe файлы точно так же, как и в Windows.

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

Скриншот 3

Потом программа Wine попросит загрузить и установить необходимые для корректной работы пакеты (в случае их отсутствия в системе). Нажимаем «Установить» и ждем окончания процесса установки этих пакетов.

Скриншот 4

После чего запустится установка программы, в нашем случае установка Notepad++, и этот процесс ничем не будет отличаться от установки в Windows, ведь это тот же самый установщик.

Более подробно посмотреть на процесс установки Notepad++ Вы можете в материале – Установка Notepad++ в Linux Mint

Шаг 4 – Запуск программы

После окончания установки ярлык программы появится в меню, а также на рабочем столе, если Вы поставили соответствующую галочку в процессе установки программы.

Скриншот 5

Для того чтобы запустить программу, просто щелкаете по ярлыку.

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

Да и тогда, когда установка пройдет успешно, никто не дает гарантии, что приложение будет работать корректно, т.е. так же как в Windows.

Видео-инструкция

На сегодня это все, надеюсь, материал был Вам полезен, пока!

Как работает Wine

Wine — это свободное программное обеспечение для запуска Windows-приложений на нескольких POSIX-совместимых операционных системах, включая Linux, macOS и BSD.

Если вы любите Linux, то наверняка когда-то запускали Wine. Возможно, для какой-то «важной» программы Windows, у которой нет аналога под Линуксом, или поиграться. Забавный факт: даже Steam Deck от Valve запускает игры через оболочку на основе Wine (она называется Proton).

За последний год я намучился с отладчиком, который позволяет одновременно дебажить и Wine, и Windows-приложение в нём. Разобраться во кишочках Wine оказалось очень интересно! Я-то раньше много им пользовался, но никогда не понимал механику целиком. Можно взять файл Windows — и просто запустить его в Linux без каких-либо изменений. Если вы хотите знать, как это сделано, добро пожаловать под кат.

Дисклеймер. В статье реальность сильно упрощается, а многие детали игнорируются. Текст даёт общее представление, как работает Wine.

© «Время приключений» (1 сезон, 18 серия) — прим. пер.

Wine — не эмулятор!

Прежде чем разбираться в работе Wine, нужно сказать, чем он НЕ является. Вообще, W.I.N.E. — это рекурсивный акроним, который расшифровывается как «Wine Is Not an Emulator». Почему? Потому что есть куча отличных эмуляторов и для старых архитектур, и для современных консолей, а Wine принципиально реализован по-другому. Давайте вкратце рассмотрим, как вообще работают эмуляторы.

Представьте простую игровую приставку, которая понимает две инструкции:

  • push — пушит заданное значение в стек
  • setpxl — достаёт три значения из стека и рисует пиксель с цветом arg1 в точке (arg2, arg3)
> dump-instructions game.rom . # рисуем красную точку по координатам (10,10) push 10 push 10 push 0xFF0000 setpxl # рисуем зелёную точку по координатам (15,15) push 15 push 15 push 0x00FF00 setpxl

Бинарный файл игры (или картридж ROM) представляет собой последовательность таких инструкций, которые аппаратное обеспечение может загрузить в память и выполнить. Нативное железо выполняет их в натуральном режиме, но как запустить старый картридж на современном ноуте? Для этого делаем эмулятор — программу, которая загружает ROM из картриджа в оперативную память и выполняет его инструкции. Это интерпретатор или виртуальная машина, если хотите. Реализация эмулятора для нашей приставки с двумя инструкциями будет довольно простой:

enum Opcode < Push(i32), SetPixel, >; let program: Vec = read_program("game.rom"); let mut window = create_new_window(160, 144); // Виртуальный дисплей 160x144 пикселей let mut stack = Vec::new(); // Стек для передачи аргументов for opcode in program < match opcode < Opcode::Push(value) => < stack.push(value); >Opcode::SetPixel => < let color = stack.pop(); let x = stack.pop(); let y = stack.pop(); window.set_pixel(x, y, color); >> >

Настоящие эмуляторы намного сложнее, но основная идея та же: поддерживать некоторый контекст (память, регистры и т.д.), обрабатывать ввод (клавиатура/мышь) и вывод (например, рисование в каком-то окне), разбирать входные данные (ROM) и выполнять инструкции одну за другой.

Разработчики Wine могли пойти по этому пути. Но есть две причины, почему они так не поступили. Во-первых, эмуляторы и виртуальные машины тормозные по своей сути — там огромный оверхед на программное выполнение каждой инструкции. Это нормально для старого железа, но не для современных программ (тем более видеоигр, которые требовательны к производительности). Во-вторых, в этом нет необходимости! Linux/macOS вполне способны запускать двоичные файлы Windows нативно, их нужно только немного подтолкнуть…

Давайте скомпилируем простую программу для Linux и Windows и сравним результат:

int foo(int x) < return x * x; >int main(int argc)

Слева — Linux, справа — Windows

Результаты заметно отличаются, но набор инструкций фактически один и тот же: push , pop , mov , add , sub , imul , ret .

Если бы у нас был «эмулятор», который понимает эти инструкции, то смог бы выполнить обе программы. И такой «эмулятор» существует — это наш CPU.

Как Linux запускает бинарники

Прежде чем запускать чужеродный двоичный файл, давайте разберёмся, как запускается под Linux родной бинарник.

❯ cat app.cc #include int main() < printf("Hello!\n"); return 0; >❯ clang app.cc -o app ❯ ./app Hello! # работает!

Довольно просто, но давайте копнём глубже. Если сделать .app ?

❯ ldd app linux-vdso.so.1 (0x00007ffddc586000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f743fcdc000) /lib64/ld-linux-x86-64.so.2 (0x00007f743fed3000) ❯ readelf -l app Elf file type is DYN (Position-Independent Executable file) Entry point 0x1050 There are 13 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040 0x00000000000002d8 0x00000000000002d8 R 0x8 INTERP 0x0000000000000318 0x0000000000000318 0x0000000000000318 0x000000000000001c 0x000000000000001c R 0x1 [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] . 

Самое главное, что .app — это динамически исполняемый файл. Он зависит от некоторых динамических библиотек и требует их присутствия в рантайме. Иначе не запустится. Другой интересный момент — запрос интерпретатора ( requesting program interpreter в последней строке листинга). Какой ещё интерпретатор? Я думал, что C++ — компилируемый язык, в отличие от Python…

В данном контексте интерпретатор — это «динамический загрузчик». Специальный инструмент, которая запускает исходную программу: разрешает и загружает её зависимости, а затем передаёт ей управление.

❯ ./app Hello! # Работает! ❯ /lib64/ld-linux-x86-64.so.2 ./app Hello! # Тоже работает! # Домашнее задание: запустите это и попробуйте понять смысл выдачи. ❯ LD_DEBUG=all /lib64/ld-linux-x86-64.so.2 ./app

При запуске исполняемого файла ядро Linux определяет, что файл динамический и требует загрузчика. Затем оно запускает загрузчик, который выполняет всю работу. Это можно проверить, если запустить программу под отладчиком:

❯ lldb ./app (lldb) target create "./app" Current executable set to '/home/werat/src/cpp/app' (x86_64). (lldb) process launch --stop-at-entry Process 351228 stopped * thread #1, name = 'app', stop reason = signal SIGSTOP frame #0: 0x00007ffff7fcd050 ld-2.33.so`_start ld-2.33.so`_start: 0x7ffff7fcd050 : movq %rsp, %rdi 0x7ffff7fcd053 : callq 0x7ffff7fcdd70 ; _dl_start at rtld.c:503:1 ld-2.33.so`_dl_start_user: 0x7ffff7fcd058 : movq %rax, %r12 0x7ffff7fcd05b : movl 0x2ec57(%rip), %eax ; _dl_skip_args Process 351228 launched: '/home/werat/src/cpp/app' (x86_64)

Мы видим, что первая выполненная инструкция находится в библиотеке ld-2.33.so , а не в бинарнике .app .

Подводя итог, запуска динамически связанного исполняемого файла в Linux выглядит примерно так:

  1. Ядро загружает образ (≈ двоичный файл) и видит, что это динамический исполняемый файл
  2. Ядро загружает динамический загрузчик ( ld.so ) и передаёт ему управление
  3. Динамический загрузчик разрешает зависимости и загружает их
  4. Динамический загрузчик возвращает управление исходному двоичному файлу
  5. Оригинальный двоичный файл начинает выполнение в _start() и в конечном итоге доходит до main()
❯ ./HalfLife4.exe -bash: HalfLife4.exe: cannot execute binary file: Exec format error

Однако если пропустить шаги с первого по четвёртый и каким-то образом перескочить на пятый, то теоретически должно сработать, верно? Ведь с точки зрения операционной системы что значит «запустить» бинарный файл?

В каждом исполняемом файле есть раздел .text со списком сериализованных инструкций CPU:

❯ objdump -drS app app: file format elf64-x86-64 . Disassembly of section .text: 0000000000001050 : 1050: 31 ed xor %ebp,%ebp 1052: 49 89 d1 mov %rdx,%r9 1055: 5e pop %rsi 1056: 48 89 e2 mov %rsp,%rdx 1059: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp 105d: 50 push %rax 105e: 54 push %rsp 105f: 4c 8d 05 6a 01 00 00 lea 0x16a(%rip),%r8 # 11d0 1066: 48 8d 0d 03 01 00 00 lea 0x103(%rip),%rcx # 1170 106d: 48 8d 3d cc 00 00 00 lea 0xcc(%rip),%rdi # 1140 1074: ff 15 4e 2f 00 00 call *0x2f4e(%rip) # 3fc8 107a: f4 hlt 107b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) . 

Чтобы «запустить» бинарный файл, ОС загружает его в память (в частности, раздел .text ), устанавливает указатель текущей инструкции на адрес, где находится код, и всё — исполняемый файл типа «запущен». Как сделать это для исполняемых файлов Windows?

Легко! Просто возьмём код из исполняемого файла Windows, загрузим в память, направим %rip в нужное место — и CPU с радостью выполнит этот код! Если архитектура процессора одинаковая, то процессору вообще без разницы, откуда выполнять ассемблерные инструкции.

Hello, Wine!

По сути, Wine — это «динамический загрузчик» для исполняемых файлов Windows. Это родной двоичный файл Linux, поэтому может нормально запускаться, и он знает, как работать с EXE и DLL. То есть своего рода эквивалент ld-linux-x86-64.so.2 :

# запуск бинарника ELF ❯ /lib64/ld-linux-x86-64.so.2 ./app # запуск бинарника PE ❯ wine64 HalfLife4.exe

Здесь wine64 загружает исполняемый файл Windows в память, анализирует его, выясняет зависимости, определяет, где находится исполняемый код (т. е. раздел .text ), и переходит в этот код.

Примечание. В действительности он переходит к чему-то вроде ntdll.dll!RtlUserThreadStart() , это точка входа в «пространство пользователя» в мире Windows. Потом в mainCRTStartup() (эквивалент _start ), и в сам main() .

На данный момент наша Linux-система выполняет код, изначально скомпилированный для Windows, и всё вроде бы работает. За исключением системных вызовов.

Системные вызовы

Системные вызовы (syscall) — вот где основные сложности. Это вызовы к функциям, которая реализованы не в бинарнике или динамических библиотеках, а в родной ОС. Набор системных вызовов представляет системный API операционной системы. В нашем случае это Windows API.

Примеры системных вызовов в Linux: read , write , open , brk , getpid

Примеры в Windows: NtReadFile , NtCreateProcess , NtCreateMutant ��

Системные вызовы не являются обычными вызовами функций в коде. Открытие файла, например, должно выполняться самим ядром, поскольку именно оно следит за файловыми дескрипторами. Поэтому приложению нужен способ как бы «прервать своё выполнение» и передать управление ядру (эта операция обычно называется переключением контекста).

Набор системных функций и способы их вызова в каждой ОС разные. Например, в Linux для вызова функции read() наш бинарник записывает в регистр %rdi дескриптор файла, в регистр %rsi — указатель буфера, а в %rdx — количество байт для чтения. Однако в ядре Windows нет функции read() ! Ни один из аргументов не имеет там смысла. Бинарник Windows использует свой способ выполнения системных вызовов, который не сработает в Linux. Не будем здесь углубляться детали системных вызовов, например, вот отличная статья о реализации в Linux.

Скомпилируем ещё одну небольшую программу и сравним сгенерированный код в Linux и Windows:

#include int main()

Слева — Linux, справа — Windows

На этот раз мы вызываем функцию из стандартной библиотеки, которая в конечном итоге выполняет системный вызов. На скриншоте выше версия Linux вызывает puts , а версия Windows — printf . Эти функции из стандартных библиотек ( libc.so в Linux, ucrtbase.dll в Windows) для упрощения взаимодействия с ядром. Под Linux сейчас частенько собирают статически связанные бинарники, не зависимые от динамических библиотек. В этом случае реализация puts встроена в двоичный файл, так что libc.so не задействуется в рантайме.

Под Windows до недавнего времени «системные вызовы bcgjkmpjdfkb только вредоносные программы» [нет источника] (вероятно, это шутка автора — прим. пер.). Обычные приложения всегда зависят от kernel32.dll/kernelbase.dll/ntdll.dll , где скрывается низкоуровневая магия тайного общения с ядром. Приложение просто вызывает функцию, а библиотеки заботятся об остальном:

источник

В этом месте вы наверное поняли, что будет дальше. ��

Трансляция системных вызовов в рантайме

А что, если «перехватывать» системные вызовы во время выполнения программы? Например, когда приложение вызывает NtWriteFile() , мы берём управление на себя, вызываем write() , а потом возвращаем результат в ожидаемом формате — и возвращаем управление. Должно сработать. Быстрое решение в лоб для примера выше:

// HelloWorld.exe lea rcx, OFFSET FLAT:`string' call printf ↓↓ // «Фальшивый» ucrtbase.dll mov edi, rcx // Преобразование аргументов в Linux ABI call puts@PLT // Вызов реальной реализации Linux ↓↓ // Real libc.so mov rdi, // запись в STDOUT mov rsi, edi // указатель на "Hello" mov rdx, 5 // сколько символов писать syscall

По идее, можно сделать собственную версию ucrtbase.dll со специальной реализацией printf . Вместо обращения к ядру Windows она будет следовать формату интерфейсов Linux ABI и вызывать функцию write из библиотеки libc.so . Однако на практике мы не можем изменять код этой библиотеки по ряду причин — это муторно и сложно, нарушает DRM, приложение может статически ссылаться на ucrtbase.dll и т. д.

Поэтому вместо редактирования бинарника мы внедримся в промежуток между исполняемым файлом и ядром, а именно в ntdll.dll . Это «ворота» в ядро, и Wine действительно предоставляет собственную реализацию. В последних версиях Wine решение состоит из двух частей: ntdll.dll (библиотека PE) и ntdll.so (библиотека ELF). Первая часть — это тоненькая прокладка, которая просто перенаправляет вызовы в ELF-аналог. А уже он содержит специальную функцию __wine_syscall_dispatcher , которая выполняет магию преобразования текущего стека из Windows в Linux и обратно.

Поэтому в Wine системный вызов выглядит следующим образом:

Диспетчер системных вызовов — это мост между мирами Windows и Linux. Он заботится о соглашениях и стандартах для системных вызовов: выделяет пространство стека, перемещает регистры и т. д. Когда выполнение переходит к библиотеке Linux ( ntdll.so ), мы можем свободно использовать любые нормальные интерфейсы Linux (например, libc или syscall ), реально читать/записывать файлы, занимать/отпускать мьютексы и так далее.

И это всё?

Звучит почти слишком просто. Но так и есть. Во-первых, под Windows много разных API. Они плохо документированы и имеют известные (и неизвестные, ха-ха) ошибки, которые следует воспроизвести в точности. (Вспомните, как при разработке Windows 95 туда скопировали утечку памяти из SimCity, чтобы популярная игра не крашилась в новой ОС. Возможно, такие специфические вещи приходится воспроизводить под Linux для корректной работы конкретных программ — прим. пер.). Большая часть исходного кода Wine — это реализация различных Windows DLL.

Во-вторых, системные вызовы можно выполнять по-разному. Технически ничто не мешает Windows-приложению выполнить прямой системный вызов через syscall , и в идеале это тоже должно работать (как мы уже говорили, Windows-игры делают всякие безумные вещи). В ядре Linux специальный механизм для обработки таких ситуаций, который, конечно, добавляет сложности.

В-третьих, весь этот бардак 32 vs 64 бит. Есть много старых 32-битных игр, которые никогда не перепишут на 64 бита. В Wine есть поддержка обеих платформ. И это тоже плюс к общей сложности.

В-четвертых, мы даже не упомянули wine-server — отдельный процесс Wine, который поддерживает «состояние» ядра (открытые дескрипторы файлов, мьютексы и т. д.).

И последнее… о, так вы хотите запустить игру? А не просто hello world? Ну так это совсем другое дело! Тогда нужно разобраться с DirectX, со звуком (привет, PulseAudio, старый друг), устройствами ввода (геймпады, джойстики) и т. д. Куча работы!

Wine разрабатывался в течение многих лет и прошёл долгий путь. Сегодня вы без проблем запускаете под Linux самые последние игры, такие как Cyberpunk 2077 или Elden Ring. Чёрт возьми, иногда производительность Wine даже выше, чем у Windows! В какое замечательное время мы живём…

P. S. На всякий случай повторим дисклеймер: статья даёт только базовое представление о работе Wine. Многие детали упрощены или опущены. Так что не судите очень строго, пожалуйста.

  • Linux
  • Wine
  • эмулятор
  • интерпретатор
  • виртуальная машина
  • динамический загрузчик
  • ядро Linux
  • ELF
  • PE
  • формат исполняемого файла
  • системные вызовы
  • Windows API
  • переключение контекста
  • системная библиотека
  • libc.so
  • ucrtbase.dl
  • Linux ABI
  • ntdll.dll
  • Windows DLL
  • Блог компании Дата-центр «Миран»
  • Системное программирование
  • Разработка игр
  • Разработка под Linux
  • Софт

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *