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 с подтверждением загрузки пакетов.

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

Для установки мы использовали последнюю стабильную версию 3.0.
Установка Windows-программ в Linux
Установим с помощью Wine в Linux какую-нибудь виндовую программу, например, текстовый редактор Notepad++.
Переходим в папку с исполняемым exe -файлом, открываем текущее расположение в терминале через контекстное меню.

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

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

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

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

Допустим, вы установили win-программу, но не можете ее найти среди других установленных программ.
Откройте q4wine, нажмите Ctrl + Z и кликните по иконке обзора в поле «Программа».

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

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

И win-приложение будет запущено.
Как в 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 (Обзор приложений) на левой боковой панели.

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

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

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

Вы получите представление о том, что будет работать, а что нет. Также здесь будет приведена процедура установки, если для установки потребуются какие-либо дополнительные задачи.
Начало работы с Wine
Прежде чем приступить к установке и запуску приложений в Wine, мы должны иметь четкое представление о некоторых вещах и о том, как настроить Wine для использования:
WinePrefix
Приложениям Windows необходим диск C:. Wine использует для этой цели виртуальный диск C:. Каталог этого виртуального диска C: называется wineprefix. Прежде всего, нам нужно создать wineprefix. Для этого откройте терминал и введите следующую команду:
winecfg
Это создаст wineprefix и откроет окно конфигурации для Wine. Вы можете изменить параметры конфигурации, если хотите, или оставить все как есть и закрыть его. Теперь вы можете найти виртуальный диск C: по адресу
$HOME/.wine/c_drive

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

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

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

Завершите установку и перейдите в каталог установки [ $HOME/.wine/drive_c/Program Files/7-zip/ ] из браузера файлов.
Щелкните правой кнопкой мыши на файле 7zFM.exe и выберите Свойства > Открыть с помощью.

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

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

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

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

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

Вы можете использовать 7-zip так же, как и в Windows — для извлечения и создания архивов и тому подобного.
Давайте сделаем все (намного) проще
Вы могли заметить, что в Wine Application Database при обзоре каждой версии приложения упоминается конкретная версия Wine.
Это связано с быстрыми темпами развития Wine. Хотя приложение работает с текущей версией Wine, оно может не работать с будущей версией из-за внесенных изменений.
Кроме того, я упоминал об установке каждого приложения в свой собственный свежий wineprefix. Таким образом, у приложения нет шансов помешать другому. И делать все это вручную, как правило, из терминала, отнимает много времени, утомляет и порой сбивает с толку.
На помощь приходит PlayOnLinux. Он предоставляет удобный интерфейс для выполнения всех этих действий. Для установки PlayOnLinux на Ubuntu просто выполните эту команду:
sudo apt install playonlinux

С помощью 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, оно будет установлено в отдельный wineprefix. Давайте установим VLC:


После этого начнется загрузка установочных файлов VLC. А затем проведет вас через весь остальной процесс. Это довольно просто.
Установка DLL или компонентов Windows и другое
Вы можете выбрать wineprefix из winetricks и установить различные библиотеки и компоненты, необходимые для запуска приложения, а также выполнить другие операции.


Примечание: Если использование winetricks кажется вам сложным, это совершенно нормально. Я тоже так считаю. По этой причине я всегда использую PlayOnLinux. PlayOnLinux может делать все, что вам может понадобиться от winetricks.
Для получения дополнительной информации вы можете ознакомиться с FAQ и документацией по Wine.
Я надеюсь, что это руководство для начинающих по использованию Wine в Linux будет вам полезно. Теперь вы можете запускать программы Windows в Linux без установки виртуальной машины или двойной загрузки.
Сообщите нам, если у вас есть вопросы или мнения, в разделе комментариев ниже.
Как запустить Windows-приложение в Linux?
Всем привет! Практически у всех начинающих пользователей Linux, которые только перешли с Windows, возникает один и тот же вопрос – а как в Linux запустить программу (игру), которая была в Windows? Иными словами, как запустить программу или игру, которая была разработана для Windows, в Linux, т.е. в другой операционной системе. В этом материале я расскажу Вам, можно ли это сделать, и если можно, то как.

Можно ли запустить Windows-приложение в Linux?
Для начала обязательно отмечу, что Linux – это совсем другая платформа, не Windows и не совместимая с ней, поэтому абсолютно любая программа или игра, разработанная для Windows, запускается только на Windows.
На заметку! Новичкам рекомендую почитать мою книгу «Linux для обычных пользователей» – в ней я подробно рассказываю про основы операционной системы Linux, и как пользоваться этой системой без командной строки.
Однако, так как эти вопросы задаются, и возник спрос, существует возможность запускать Windows-приложения в Linux, но это не стандартная возможность, которая не гарантирует нормального функционирования программы, да и не все программы так можно запустить, а еще к тому же, за счет того, что запускаются именно Windows-приложения, значительно снижается безопасность системы. Поэтому лучше не использовать возможность, которую я опишу чуть ниже, а пользоваться стабильными приложениями, разработанными именно для Linux.
Обзор инструментов Wine, Winetricks и PlayOnLinux
Итак, если у Вас все-таки остро стоит задача запустить Windows-кую программу в Linux, то существует специальная программа под названием Wine.

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.

По факту 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.
Таким образом, для запуска установки программы мы просто щелкаем двойным кликом по скаченному файлу.

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

После чего запустится установка программы, в нашем случае установка Notepad++, и этот процесс ничем не будет отличаться от установки в Windows, ведь это тот же самый установщик.
Более подробно посмотреть на процесс установки Notepad++ Вы можете в материале – Установка Notepad++ в Linux Mint
Шаг 4 – Запуск программы
После окончания установки ярлык программы появится в меню, а также на рабочем столе, если Вы поставили соответствующую галочку в процессе установки программы.

Для того чтобы запустить программу, просто щелкаете по ярлыку.
Как видите, в нашем случае проблем с установкой программы в 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 выглядит примерно так:
- Ядро загружает образ (≈ двоичный файл) и видит, что это динамический исполняемый файл
- Ядро загружает динамический загрузчик ( ld.so ) и передаёт ему управление
- Динамический загрузчик разрешает зависимости и загружает их
- Динамический загрузчик возвращает управление исходному двоичному файлу
- Оригинальный двоичный файл начинает выполнение в _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
- Софт