Статическая рекомпиляция
Статическая рекомпиляция (Статрекомп, англ. Static Recompilation, он же AOT-перевод бинарников, для илиты — диванное портирование без сорцов) — священный Грааль эмуляторщиков, влажная мечта ретрогеймеров с калькуляторами вместо нормальных компов и главный источник анальной боли для старых си-девелоперов, познавших дао дизассемблера. Берется скомпилированный бинарник древней игры под приставку с марсианской процессорной архитектурой, 1 раз прогоняется через специальный транслятор и превращается в нативный исполняемый файл под твою текущую операционку. Без эмулятора, с жором в 1% процессора и рендером в 4K прямо на микроволновке.
С 2010 по 2024 год считалась среди разработчиков безумной утопией из-за таких явлений, как самомодифицирующийся код, косвенные переходы в середину команд и железозависимые костыли. Однако в период 2024–2026 годов плотину прорвало: сцена утонула в десятках портов, а на Reddit и GitHub вспыхнула гражданская война между фанатами ручного реверса и адептами нейросетей.
|
Step 1: convert the PS2 code into an assembler code. Step 2: convert the assembler code into a higher language code (like c++)... Now you have a complete built of game, which is full playable! |
||
| — Tommy87 на форуме PCSX2, 2010 год | ||
|
Since step 2's not feasible for computers and many months or years of a programmer's time if done manually, I can safely stop reading there. |
||
| — Разработчик PCSX2 Pseudonym, отправляя мечтателя в биореактор | ||
|
Fuck AI vibe coding bullshit. |
||
| — Манифест команды DK64 Rekongpiled, лето 2026 года | ||
СутьЪ[править]
Каждый малолетний любитель ретро-игр регулярно оставляет на форумах один и тот же высер: Зачем ваш эмулятор грузит 16 ядер процессора, чтобы выдать 20 кадров в секунду в игре для Nintendo 64? Почему нельзя тупо взять машинный код с диска, перевести его в команды x86 и сохранить как обычный .exe?
Разработчики эмуляторов после таких вопросов обычно тянутся за валидолом. Исторически эмуляция развивалась по 2 направлениям:
- Интерпретаторы: Программа берет 1 команду старого чипа, разбирает её по байтам, вручную двигает виртуальные регистры в памяти и ползет к следующей. Безопасно, аутентично, но скорость падает в 50–100 раз.
- Динамическая рекомпиляция (JIT, Dynarec): Код читается кусками прямо во время игры, компилируется на лету под твой процессор, кладется в кэш и исполняется. Так работают PCSX2, RPCS3 и Dolphin. Быстро, но жрет системные ресурсы и регулярно заикается на компиляции новых блоков.
Статическая рекомпиляция шлет оба подхода лесом. Бинарник переводится целиком до запуска (Ahead-of-Time). Каждая инструкция старого процессора превращается в эквивалентную инструкцию ПК (или сразу в код на Си), собирается обычным Clang или GCC и линкуется с самодельным рантаймом, заменяющим видеочип и ядро приставки.
У диванных теоретиков план выглядит безупречно:
- Никаких эмуляторов в фоне.
- Запуск за 0.01 секунды без лагов кэша шейдеров.
- 480 кадров в секунду без поломки игровой физики.
- Ультраширокие мониторы, прицеливание мышью и трассировка лучей через движки вроде RT64.
В реальности авторы коммерческих игр 1990-х и 2000-х писали код ногами ради экономии 2 байт оперативной памяти, из-за чего автоматические трансляторы десятилетиями давились фатальными ошибками.
Терминология[править]
Чтобы школота не путала термины, расклад по понятиям следующий:
- Эмуляция: Запуск программного ящика, воспроизводящего железо консоли до последнего транзистора. Внутрь ящика кладется оригинальный образ диска. ПК пашет как трактор.
- Декомпиляция (Matching Decompilation): Чистый мазохизм. Толпа нердов годами сидит в Ghidra и IDA Pro, вручную подбирая код на Си под старый компилятор, пока полученный бинарник не совпадет с оригиналом байт-в-байт на 100%. Так восстановили Super Mario 64, The Legend of Zelda: Ocarina of Time и Perfect Dark. На 1 тайтл уходит от 3 до 7 лет каторжного труда.
- Статическая рекомпиляция: Прагматичный срез углов. Никто не пытается понять замысел японского программиста. Утилита берет команду MIPS `addiu $r4, $r4, 0x20` и вслепую выплевывает Си-код `ctx->r4 = ADD32(ctx->r4, 0x20);`. Читать это глазами невозможно, но компилятор собирает нативный `.exe` за пару минут. Сроки релиза порта сокращаются с 5 лет до пары недель.
Предыстория[править]
Попытки переводить бинарники без переписывания исходников предпринимались давно:
- В 1996 году фирма DEC выпустила утилиту FX!32 для запуска программ Windows x86 на процессорах Alpha. Использовался гибрид: игра стартовала в эмуляторе, фоновый сервис собирал профиль вызовов, а ночью транслировал горячий код в нативные инструкции Alpha.
- В 1999 году вышел эмулятор Nintendo 64 — UltraHLE. Он показал эффективность высокоуровневой эмуляции (HLE): вместо моделирования кремния достаточно перехватывать системные вызовы библиотек (libultra).
- В 2000 году эмулятор Corn доказал, что статический транслятор N64 выдает дикую скорость на древних процессорах Pentium 166 MMX. Проект быстро загнулся, намертво разбившись о динамический код.
- В 2013 году Эндрю Келли (будущий создатель языка Zig) попытался статически перекомпилировать игры NES через LLVM в проекте Jamulator. Наткнувшись на гору прыжков в середину опкодов, автор признал затею нежизнеспособной.
- Apple: Купертиновцы дважды проворачивали этот трюк в коммерческих масштабах: в 1-й версии Rosetta при уходе с PowerPC на Intel, и в 2020 году в Rosetta 2 при переходе на чипы Apple Silicon (ARM64). Чтобы статрекомп не падал, Apple аппаратно встроила в кремний процессоров M1 поддержку модели памяти x86 (TSO), а для нераспознанного кода оставила скрытый JIT.
Инцидент с Tommy87[править]
В мае 2010 года на форуме эмулятора PCSX2 немецкий пользователь с ником tommy87 открыл тред Static Recompilation ..?!, мгновенно вошедший в анналы истории.
План пациента состоял из 5 шагов:
- Шаг 1: перевести код PS2 в ассемблер.
- Шаг 2: автоматически перевести ассемблер в C++ или псевдокод.
- Шаг 3: вручную оптимизировать графические вызовы под ПК.
- Шаг 4: автоматизировать этот процесс для конкретной игры.
- Шаг 5: повторить для оставшихся 3000 игр библиотеки PS2.
Разработчики эмулятора (refraction, rama, pseudonym) попытались донести до автора, что процессор Emotion Engine с векторными блоками VU0/VU1 и видеочипом с шиной на 26 гигабайт в секунду не поддаются линейной трансляции.
Градус неадеквата рос с каждым постом:
- Разработчик: У тебя есть пара сотен гигабайт оперативной памяти под все варианты состояний?
- Томми: Ассемблер на диске — это и есть исходный код! Что, по-вашему, записано на болванке? Бананы?!
- Разработчик: Шаг 2 технически невыполним для машин и требует сотен лет ручной работы. Дальше можно не читать.
- Томми: Не говорите, что это невозможно! В Final Fantasy X на моем Athlon 1.9 ГГц скорость падает до 70%. Я напишу этот транслятор сам, когда будет время, а вы мне поможете!
Фраза про бананы на диске стала локальным мемом на 15 лет. Самое ироничное, что к 2026 году безумные фантазии Томми начали материализоваться на практике.
Матчасть[править]
Причины, по которым компьютеры не умеют просто взять и перекомпилировать чужой бинарник, упираются в базовые свойства архитектуры фон Неймана.
Код и данные[править]
В исполняемых файлах команды процессора и сырые массивы данных валяются вперемешку в одной секции памяти.
- Компилятор запросто кладет таблицу смещений прямо посреди исполняемого блока `.text`.
- Наивный дизассемблер парсит байты подряд. Наткнувшись на 32-битное число с плавающей точкой `0x3F800000` (число 1.0f), транслятор принимает его за машинную инструкцию, превращает в бред и сбивает чтение всех последующих инструкций.
- В архитектуре x86 длина инструкций варьируется от 1 до 15 байт. Ошибка на 1 байт превращает весь оставшийся код в кашу. На MIPS и PowerPC спасает фиксированный размер команды в 4 байта.
Косвенные прыжки[править]
Обычный переход `jmp 0x00401000` транслируется элементарно: подставляется вызов нужной Си-функции.
Проблемы начинаются на конструкциях вида `jr $t0` (переход по адресу, лежащему в регистре). Значение в регистре вычисляется прямо во время игры на основе действий игрока, таймеров и состояния физики.
- Угадать адрес перехода заранее невозможно.
- Пространство адресов для 32-битного регистра составляет 4294967296 вариантов.
- Попытка вычислить все возможные пути исполнения натыкается на доказанную Тьюрингом Проблему Остановки. Пропуск 1 адреса гарантирует моментальный вылет в `Segmentation Fault`.
Самомодификация[править]
На старых системах (PlayStation 1, Game Boy, NES) разработчики для экономии памяти перезаписывали опкоды прямо в оперативной памяти и сразу прыгали на измененный участок. Статически переведенный код выполняется процессором напрямую. Если игра перепишет байты в своем буфере, ПК этого даже не заметит, продолжая крутить старый код.
Начиная с Xbox 360 и PlayStation 3 лавочку прикрыли: операционные системы ввели защиту W^X (память можно либо модифицировать, либо исполнять, но не одновременно), что избавило рекомпиляторы от этого ада на современных консолях.
Регистры[править]
Разница между наборами регистров заставляет компиляторы страдать:
- Процессор Power8 содержит 32 регистра общего назначения плюс векторные массивы. Блоки SPU консоли PlayStation 3 имеют 128 регистров шириной 128 бит каждый.
- У процессоров архитектуры x86-64 доступно всего 16 регистров общего назначения.
Лишние регистры приходится сбрасывать в оперативную память. Без агрессивной работы оптимизаторов LLVM код превращается в бесконечную медленную пересылку байтов между стеком и регистрами.
Байт-ордер[править]
- Процессоры ПК работают в стандарте Little-Endian (младший байт впереди).
- Процессоры Nintendo 64, GameCube, Wii, Xbox 360 и PS3 работают в Big-Endian (старший байт впереди).
Каждое чтение и запись значений размером в 16, 32 и 64 бита требует ручного переворота байтов. Ошибка в 1 переменной приводит к тому, что счетчик жизней превращается в число 16777216, а анимация ломает геометрию уровня.
Революция 2024–2026[править]
В 2024 году программист Mr-Wiseguy выкатил инструмент N64Recomp, изменивший правила игры.
N64Recomp[править]
Автор отказался от попыток построить идеальный декомпилятор и собрал утилитарный конвейер:
- На вход подается бинарник формата ELF вместе с символьной картой функций (добытой из частичных декомпиляций).
- Библиотека rabbitizer декодирует инструкции MIPS.
- Команды переводятся в Си-код почти 1 в 1. Задержки ветвления (branch delay slots) закрываются дублированием кода.
- Табличные прыжки трансформируются в конструкции `switch-case`.
- На выходе создаются тысячи мелких Си-файлов (по 1 на оригинальную функцию).
- Код линкуется с рантаймом N64ModernRuntime и графическим транслятором RT64 авторства DarioSamo.
Пилотный релиз Zelda 64: Recompiled (порт The Legend of Zelda: Majora’s Mask) выдал результаты, недостижимые на классических эмуляторах:
- 480 кадров в секунду на мониторах с высокой герцовкой с кастомной интерполяцией кадров без ускорения игровой логики.
- Нулевой инпут-лаг и мгновенные загрузки между локациями.
- Нативное управление камерой стиком и гироскоп.
- Полная поддержка широкоформатных экранов без обрезания интерфейса.
Вслед за Зельдой сообщество выпустило рекомпы Banjo-Kazooie, Star Fox 64, Mario Kart 64, Dinosaur Planet, Extreme-G, Bomberman 64 и Snowboard Kids 2.
Зоопарк платформ[править]
Успех N64 спровоцировал экспансию технологии на другие консоли.
Xbox 360[править]
Процессор Xenon содержит 3 двухпоточных ядра PowerPC с частотой 3.2 ГГц и векторным набором VMX128. Эмулировать его тяжело даже для топовых Core i9.
Проект Sonic Unleashed Recompiled доказал жизнеспособность AOT-перевода PowerPC в нативный C++ с выводом графики через Direct3D 12. На базе этих наработок был создан общий фреймворк ReXGlue, позволивший запустить на ПК коммерческие тайтлы: Blue Dragon, Kameo: Elements of Power, Viva Piñata: Trouble in Paradise и Naughty Bear.
PlayStation 3[править]
Архитектура Cell Broadband Engine долго считалась неподъемной: главное ядро PPU плюс 6 векторных ядер SPU с изолированной памятью по 256 килобайт и обменом через контроллер DMA.
Энтузиаст sp00nznet создал проект ps3recomp:
- Парсер разбирает бинарники ELF/PRX и выдирает зашитые микропрограммы SPU.
- Код PPU и SPU транслируется раздельно. Локальная память SPU эмулируется плоским массивом в 256 КБ, а команды DMA заменяются на вызовы `memcpy`.
- Вместо операционной системы написана высокоуровневая реализация 97 системных библиотек поверх наработок эмулятора RPCS3.
- Команды видеочипа RSX переводятся в Direct3D 12 и Metal.
В чейнджлоге версии v0.10.0 описан показательный баг из игры You Don't Know Jack. Процесс намертво вис на загрузке. Оказалось: мьютекс `CellSyncMutex` представляет собой ticket-lock из 2 полей: `m_freed` и `m_order`. На приставке он упакован в Big-Endian. Разработчики рекомпилятора сохранили его в обычном порядке хоста. Когда SPU освобождал мьютекс со счетом 1/1, процессор ПК читал значение как `0x01000100`, решал, что ресурс заблокирован, и цикл `TryLock` успевал прокрутиться ровно 160000000 раз вхолостую.
К осени 2026 года через ps3recomp нативно рендерились Tokyo Jungle, flOw, The Simpsons Arcade Game, Twisted Metal и Virtua Fighter 5.
PS1 и PS2[править]
Разработчик flafmg создал проект RecompOne, собрав рабочий нативный порт Castlevania: Symphony of the Night с первой плойки и начав перенос Silent Hill. Проект доказал, что архитектура MIPS R3000A переводится в современный машинный код без тяжелых накладных расходов.
На второй соньке инициативу перехватил PS2Recomp, начавший автоматический разбор инструкций Emotion Engine под ПК.
Вайб-срач[править]
В начале 2025 года в рекомпиляцию пришли большие языковые модели. Началась эпоха вайб-кодинга.
Суть драмы[править]
Новички выяснили, что если скормить ассемблер функции моделям Claude 3.5 Sonnet, Claude 3.7 или DeepSeek R1, снабдив их структурами памяти, нейросеть с вероятностью в 80–95% генерирует валидный Си-код.
Появились тулзы вроде расширения Kappa для VS Code: агент гоняет функции по кругу через утилиту `objdiff`, компилирует код, сверяет бинарный выхлоп с оригиналом и правит строчки до получения 100% совпадения.
Нашествие ботов[править]
GitHub захлестнула волна скороспелых репозиториев:
- `nesrecomp` (10 портов за неделю)
- `snesrecomp` (Mega Man X, Super Mario World)
- `gbarecomp` (пачка игр на коленке)
- `psxrecomp` (Tomba!, Digimon World)
YouTube-блогеры начали штамповать ролики о том, что эпоха эмуляции подошла к концу и любая игра портируется на ПК за 5 минут.
Джихад аутистов[править]
При детальном аудите кода выяснились критические проблемы:
- Неподдерживаемое спагетти: Код от нейросетей переполнен скрытыми дефектами. В порте Mega Man X на боссе Rangda Bangda синий глаз улетал за экран на 45 секунд из-за пропущенного флага процессора M/X. Автор порта не мог починить баг, так как не понимал логику сгенерированных инструкций.
- Поломка инфраструктуры: Чтобы скрыть ошибки генерации, вайб-кодеры правили код базовых графических движков (вроде RT64), разрушая совместимость с другими портами.
- Смерть проектов: Большинство сгенерированных портов крашились после первых уровней.
Кульминацией стал скандал вокруг Donkey Kong 64. После релиза сырого ИИ-порта ветераны реверса из сообщества DK64 Randomizer выкатили проект DK64 Rekongpiled со слоганом: Fuck AI vibe coding bullshit. Мы пишем проект руками.
Началась война на уничтожение:
- Модераторы сабреддита `r/emulation` внедрили правило номер 7, запретив публикации проектов на базе неконтролируемой генерации кода.
- В сабреддите `r/decomps` вспыхнули баталии между сторонниками быстрой генерации и сторонниками чистоты исходников.
- Авторы ИИ-портов начали заваливать GitHub жалобами, из-за чего репозитории официальных проектов (включая рекомпы Star Fox 64 и Mario Kart 64) временно блокировались администрацией платформы.
Юристы и Нинтендо[править]
|
In before Nintendo sends the C&D. |
||
| — Дежурный комментарий под любой новостью о рекомпиляции | ||
Несмотря на юридическую агрессию Nintendo, авторы N64Recomp остаются юридически неуязвимыми благодаря строгой схеме дистрибуции:
- Чистые репозитории: Проекты распространяются под лицензиями MIT и GPL, не содержат коммерческого кода и бинарников Nintendo.
- Отсутствие ассетов: В коде нет текстур, звуков, уровней и защищенных копирайтом материалов.
- Сборка на клиенте: Исполняемый файл собирается на компьютере пользователя из его личного ROM-файла, предоставленного вручную.
Прецеденты судов США (Sony Computer Entertainment v. Connectix Corp. и Sega Enterprises Ltd. v. Accolade, Inc.) гарантируют:
- Обратная разработка ради совместимости законна.
- Модификация купленного софта под личное железо подпадает под добросовестное использование (Fair Use).
Если фанат выложит готовый `.exe` с упакованными ресурсами игры на файлообменник, ему прилетит судебный иск. Если проект поставляет только скрипты сборки — юристы корпораций бессильны.
Галерея[править]
| Проект | Платформа | Метод | Статус (2026 год) | Уровень драмы |
|---|---|---|---|---|
| Zelda 64: Recompiled | Nintendo 64 | N64Recomp (MIPS → C) | Полностью играбельно | Нулевой. Всеобщий восторг. |
| Sonic Unleashed Recompiled | Xbox 360 | Ручной AOT (PowerPC → C++) | 120 FPS без просадок | Средний. Разрыв шаблона у консольщиков. |
| DK64 Rekongpiled | Nintendo 64 | Ручной человеческий рекомп | Релиз состоялся | Экстремальный. Война против нейросетей. |
| ps3recomp | PlayStation 3 | PPU/SPU трансляция | Меню и геймплей десятка игр | Высокий. Переписано 97 модулей прошивки. |
| Mario Kart Wiicompiled | Nintendo Wii | PowerPC → x86 native | Бета с мультиплеером | Умеренный. Срачи о нужности при живом Dolphin. |
| Digimon World PSX Recomp | PlayStation 1 | psxrecomp + Claude | Играбельно с модами | Высокий. Блокировка репозитория по доносам. |
| Super Mario 64 PC Port | Nintendo 64 | Matching Decompilation | Портировано на всё | Исторический винрар. |
Словарь[править]
- Ассеты — текстуры, звуки, музыка и 3D-модели. Единственная деталь игры, владение которой защищено копирайтом. Распространять нельзя.
- Байт-матчинг — доведение декомпилированного кода до состояния, когда старый компилятор собирает из него файл, идентичный оригинальному картриджу на 100%.
- Вайб-кодинг — написание софта через промпты нейросетям без глубокого понимания архитектуры процессора и структур данных.
- Оверлей — кусок кода, динамически подгружаемый с диска на место другого кода в условиях дефицита оперативной памяти консоли.
- Рантайм — программная прослойка, транслирующая запросы рекомпилированной игры к системным библиотекам ПК.