Введение

Форма двоичной перекомпиляции

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

Мотивация

Бинарный перевод обусловлен отсутствием бинарного файла для целевой платформы, отсутствием исходного кода для компиляции на целевую платформу или другими сложностями при компиляции исходного кода для целевой платформы. Статически перекомпилированные двоичные файлы могут работать быстрее, чем их эмулированные аналоги, поскольку устраняются накладные расходы, связанные с эмуляцией. Это аналогично разнице в производительности между интерпретируемыми и компилируемыми программами в общем случае.

Статический двоичный перевод

Переводчик, использующий статический двоичный перевод, стремится преобразовать весь код исполняемого файла в код, работающий на целевой архитектуре, без предварительного запуска кода, в отличие от динамического двоичного перевода. Это очень сложно сделать корректно, поскольку не весь код может быть обнаружен переводчиком. Например, некоторые части исполняемого файла могут быть доступны только через косвенные переходы, значение которых известно лишь во время выполнения. Один из таких статических двоичных переводчиков использует универсальную технологию супероптимизации с использованием peephole оптимизации (разработанную Соравом Бансалом и Алексом Эйкеном из Стэнфордского университета) для эффективного перевода между множеством пар исходных и целевых архитектур, с относительно низкими затратами на разработку и высокой производительностью результирующего двоичного кода. В экспериментах по переводу с PowerPC на x86 некоторые исполняемые файлы даже превосходили нативные версии по производительности, но в среднем их скорость составляла две трети от скорости нативных версий.

Примеры статических двоичных переводов

Honeywell предоставила программу Liberator для своих компьютеров серии Honeywell 200; она позволяла переводить программы, написанные для компьютеров серии IBM 1400, в программы для серии Honeywell 200. В 2014 году версия видеоигры StarCraft 1998 года для архитектуры ARM была создана посредством статической рекомпиляции и дополнительной обратной разработки оригинальной x86-версии. Сообщество пользователей портативной консоли Pandora самостоятельно разработало необходимые инструменты и успешно осуществило подобные переводы несколько раз. Например, в 2014 году была успешно выполнена статическая рекомпиляция с x86 на x64 для процедурного генератора ландшафта в видеоигре Cube World. Другой пример – статически рекомпилированная версия видеоигры Super Mario Bros. с NES на x86, созданная в 2013 году с использованием LLVM. В 2004 году Скотт Эллиотт и Филипп Р. Хатчинсон из Nintendo разработали инструмент для генерации C-кода из бинарного кода Game Boy, который затем можно было скомпилировать для новой платформы и связать с библиотекой аппаратного обеспечения для использования в бортовых развлекательных системах. В 1995 году Норман Рамси из Bell Communications Research и Мэри Ф. Фернандес из департамента компьютерных наук Принстонского университета разработали The New Jersey Machine Code Toolkit, включавший в себя базовый набор инструментов для статического преобразования ассемблерного кода.

Динамический двоичный перевод

Динамический двоичный перевод (ДВТ) анализирует короткую последовательность кода — как правило, порядка одного базового блока — затем переводит её и сохраняет полученную последовательность в кэше. Код переводится только по мере обнаружения и при возможности, а инструкции перехода направляются на уже переведенный и сохраненный код (мемоизация). Динамический двоичный перевод отличается от простой эмуляции (устранением основного цикла чтения, декодирования и выполнения эмулятора — серьезного узкого места производительности), что достигается за счет значительных накладных расходов во время перевода. Предполагается, что эти накладные расходы компенсируются многократным выполнением переведенных последовательностей кода. Более продвинутые динамические переводчики используют динамическую перекомпиляцию, при которой переведенный код инструментируется для определения наиболее часто выполняемых его частей, которые затем подвергаются агрессивной оптимизации. Этот метод напоминает JIT-компилятор, и, фактически, такие компиляторы (например, технология Sun HotSpot) можно рассматривать как динамические переводчики из виртуального набора инструкций (байтового кода) в реальный.

Примеры динамических двоичных переводов в программном обеспечении

Apple Computer реализовала динамический эмулятор перевода для кода M68K в своей линейке Macintosh PowerPC – динамическую двоичную систему трансляции, сочетающую быструю интерпретацию кода с двухфазной динамической трансляцией для прозрачного и точного выполнения приложений HP 9000 HP-UX на HP-UX 11i для серверов HPE Integrity. Быстрый интерпретатор ARIES эмулирует полный набор не привилегированных инструкций PA-RISC без вмешательства пользователя. В процессе интерпретации он отслеживает схему выполнения приложения и переводит только часто выполняемый код в нативный код Itanium во время выполнения. ARIES реализует двухфазную динамическую трансляцию – технику, при которой переведенный код на первом этапе собирает информацию о профиле времени выполнения, которая используется на втором этапе трансляции для дальнейшей оптимизации переведенного кода. ARIES хранит динамически переведенный код в буфере памяти, называемом кэшем кода. Последующие обращения к переведенным базовым блокам выполняются непосредственно в кэше кода и не требуют дополнительной интерпретации или трансляции. Целевые адреса переведенных блоков кода подвергаются обратной модификации для обеспечения выполнения в кэше кода в большинстве случаев. По завершении эмуляции ARIES удаляет весь переведенный код, не изменяя исходное приложение. Эмуляционный движок ARIES также реализует эмуляцию среды, которая эмулирует системные вызовы приложения HP 9000 HP-UX, доставку сигналов, обработку исключений, управление потоками, эмуляцию HP GDB для отладки и создание файлов дампа памяти для приложения. DEC создала двоичный транслятор FX!32 для преобразования приложений x86 в приложения Alpha. Согласно разделу часто задаваемых вопросов на своем веб-сайте, корпорация Intel разработала и внедрила динамический двоичный транслятор IA-32 Execution Layer, предназначенный для поддержки приложений IA-32 на системах на базе Itanium, который был включен в Microsoft Windows Server для архитектуры Itanium, а также в несколько дистрибутивов Linux, включая Red Hat и Suse. Это позволило приложениям IA-32 работать быстрее, чем при использовании нативного режима IA-32 на процессорах Itanium. Dolphin (эмулятор для GameCube/Wii) выполняет JIT-перекомпиляцию кода PowerPC в x86 и AArch64. Microsoft Virtual PC поддерживает двоичную трансляцию для 32-битных гостевых операционных систем.

Примеры динамических двоичных переводов в аппаратном обеспечении

Nvidia Tegra K1 Denver транслирует инструкции ARM через медленный аппаратный декодер в свой собственный микрокод и использует программный двоичный транслятор для часто используемого кода.