Так что это отчасти связано с вопросом о запуске сервера Windows на ARM . Таким образом, предпосылка моего вопроса заключается в том, может ли машинный код быть переведен из одной архитектуры в другую , чтобы выполнить двоичный файл в архитектуре, отличной от той, для которой он был скомпилирован.
QEMU и другие эмуляторы могут переводить инструкции на лету и, следовательно, запускать исполняемый файл на компьютере, для которого он не был скомпилирован. Почему бы не сделать этот перевод заранее, а не на лету, чтобы ускорить процесс? Из моего нескольких ограниченного знания собраний, большинство инструкций нравится MOV
, ADD
и другие должен быть переносимы между архитектурами.
Все, что не имеет прямого сопоставления, может быть сопоставлено с каким-то другим набором инструкций, так как все машины являются Turing Complete. Будет ли это слишком сложно? Разве это не сработает вообще по какой-то причине, с которой я не знаком? Будет ли это работать, но не даст лучших результатов, чем использование эмулятора?
источник
Ответы:
Краткий ответ : Вы не можете перевести скомпилированный связанный исполняемый файл. Хотя это технически возможно, это очень маловероятно (см. Ниже). Однако , если у вас есть исходный файл сборки (содержащий инструкции и метки), это очень возможно сделать (хотя, если вы каким-то образом получите исходный код сборки, если программа не написана на сборке, вы должны иметь исходный код программы как ну, так что для начала вам лучше скомпилировать его для другой архитектуры).
Длинный ответ :
Я знаю, что это может показаться простым в принципе, но на практике это практически невозможно по нескольким основным причинам. Для начала разные наборы команд используют в значительной степени разные режимы адресации, разные структуры кода операции, разные размеры слов, а в некоторых даже нет нужных вам инструкций.
Допустим, вам нужно заменить инструкцию еще
XYZ
двумя инструкциями,ABC
иDEF
. Теперь вы эффективно сместили все относительные / смещенные адреса во всей программе с этого момента, поэтому вам нужно будет проанализировать и пройти всю программу и обновить смещения (как до, так и после изменения). Теперь, скажем, одно из смещений значительно меняется - теперь вам нужно изменить режимы адресации, которые могут изменить размер адреса. Это снова заставит вас пересмотреть весь файл и пересчитать все адреса, и так далее, и так далее.Когда вы пишете программы на ассемблере, вы можете использовать метки, но процессор не использует - когда файл собран, все метки рассчитываются как относительные, абсолютные или смещенные местоположения. Вы можете понять, почему это быстро становится нетривиальной задачей и почти невозможным. Замена одной инструкции может потребовать, чтобы вы прошли через всю программу сотни раз, прежде чем двигаться дальше.
Да, но посмотрите на вопросы, которые я изложил выше. Как насчет размера слова машины? Длина адреса? У него вообще есть одинаковые режимы адресации? Опять же, вы не можете просто «найти и заменить» инструкции. Каждый сегмент программы имеет специально определенный адрес. Переходы к другим меткам заменяются литеральными или смещенными адресами памяти при сборке программы.
Вы на 100% правы, что это возможно и будет намного быстрее . Тем не менее, написание программы для достижения этой цели невероятно сложно и невероятно, если не для чего-либо, кроме вопросов, которые я изложил выше.
Если бы у вас был фактический исходный код сборки, было бы тривиально перевести машинный код в другую архитектуру набора команд. Сам машинный код, однако, собирается , поэтому без источника сборки (который содержит различные метки, используемые для вычисления адресов памяти) это становится невероятно трудным. Опять же, изменение одной инструкции может изменить смещения памяти во всей программе и потребовать сотни проходов для пересчета адресов.
Выполнение этого для программы с несколькими тысячами инструкций потребует десятков, если не сотен тысяч проходов. Для относительно небольших программ это может быть возможно, но помните, что количество проходов будет экспоненциально увеличиваться с увеличением количества машинных инструкций в программе. Для любой программы достаточно приличного размера это практически невозможно.
источник
Да, то, что вы предлагаете, может быть и было сделано. Это не слишком распространено, и я не знаю ни одной современной системы, использующей эту технику, но она определенно находится в пределах технической осуществимости.
Раньше было много сделано для того, чтобы сделать возможным перенос кода из одной системы в другую, прежде чем кто-либо достиг даже той грубой «переносимости», которую мы имеем сейчас. Он требовал комплексного анализа «источника» и мог помешать модификации кода и другим странным практикам, но это все же было сделано.
В последнее время такие системы, как IBM System / 38 - iSeries - System i, воспользовались преимуществами переносимости промежуточного кода (аналогичного байт-кодам Java), хранимого в скомпилированных программах, для обеспечения переносимости между несовместимыми архитектурами набора команд.
источник
Сам машинный код зависит от архитектуры.
Языки, обеспечивающие легкую переносимость между несколькими архитектурами (вероятно, наиболее известной из них является Java), как правило, имеют очень высокий уровень, требующий установки интерпретаторов или сред на машине для их работы.
Эти структуры или интерпретаторы написаны для каждой конкретной архитектуры системы, на которой они будут работать, и поэтому сами по себе не являются более переносимыми, чем «обычная» программа.
источник
Абсолютно, это возможно. Что такое машинный код? Это просто языкчто конкретный компьютер понимает. Думайте о себе как о компьютере, и вы пытаетесь понять книгу, написанную на немецком языке. Вы не можете сделать это, потому что вы не понимаете язык. Теперь, если бы вы взяли словарь немецкого языка и посмотрели слово «Kopf», вы бы увидели, что оно переводится на английское слово «head». Используемый вами словарь называется эмуляционным слоем в компьютерном мире. Легко ли? Ну, это становится сложнее. Возьмите немецкое слово «Schadenfruede» и переведите его на английский. Вы увидите, что в английском языке нет слова, но есть определение. Та же проблема существует в компьютерном мире, переводя вещи, которые не имеют эквивалентного слова. Это затрудняет прямые порты, так как разработчикам уровня эмуляции приходится интерпретировать, что означает это слово, и заставить главный компьютер его понимать. Иногда это не работает так, как можно было бы ожидать. Мы все видели забавные переводы книг, фраз и т. Д. В Интернете, верно?
источник
Процесс, который вы описываете, называется статической перекомпиляцией, и это было сделано, но не общепринятым способом. Это означает, что это невозможно, это было сделано много раз, но это требовало ручной работы.
Есть много исторических примеров, которые стоит исследовать, но они менее способны продемонстрировать современные проблемы. Я нашел два примера, которые должны заставить любого скептика задаться вопросом о людях, которые утверждают, что все сложно, невозможно.
Сначала этот парень сделал полную статическую архетектуру И платформу для NES ROM. http://andrewkelley.me/post/jamulator.html
Он делает несколько очень хороших замечаний, но приходит к выводу, что JIT все еще более практичен. Я на самом деле не уверен, почему он еще не знал, что для этой ситуации, это может быть тип ситуации, которую большинство людей рассматривают. Не требуя ярлыков, требуя точности полного цикла и практически не используя ABI. Если бы это было все, что было, мы могли бы выбросить концепцию в мусорное ведро и назвать это днем, но это еще не все и никогда не было ... Откуда мы это знаем? Потому что все успешные проекты не использовали этот подход.
Теперь, когда возможности менее очевидны, используйте уже имеющуюся платформу ... Starcraft на платформе Linux ARM? Да, подход работает, когда вы не ограничиваете задачу тем, что вы делаете динамически. При использовании Winlib все вызовы платформы Windows являются родными, и все, о чем мы должны беспокоиться - это архитектура.
http://www.geek.com/games/starcraft-has-been-reverse-engineered-to-run-on-arm-1587277/
Я бы бросил доллары в пончики, что замедление почти ничтожно, учитывая, что ARM ручной Пандора лишь немного сильнее, чем Pi. Инструменты, которые он использовал, находятся в этом хранилище.
https://github.com/notaz/ia32rtools
Этот парень декомпилировал очень вручную, я считаю, что процесс можно было бы значительно автоматизировать с меньшим количеством работы ... но все же это труд любви на данный момент. Не позволяйте никому говорить вам, что что-то невозможно, даже не позволяйте мне говорить вам, что это не практично ... Это может быть практично, как только вы создадите новый способ сделать это.
источник
Теоретически, да, это может быть сделано. Большая проблема, которая входит в игру, - это перевод приложения для одной операционной системы (или ядра) в другую. Существуют значительные различия между операциями низкого уровня в ядрах Windows, Linux, OSX и iOS, которые должны использовать все приложения для этих устройств.
Еще раз, теоретически, можно написать приложение, которое может разложить приложение, а также весь машинный код, связанный с операционной системой, для которой оно было скомпилировано, и затем перекомпилировать весь этот машинный код для другого устройства. Тем не менее, это было бы крайне незаконно практически в каждом случае, и было бы крайне сложно написать. Фактически, шестерни в моей голове начинают заедать, просто думая об этом.
ОБНОВИТЬ
Несколько комментариев ниже, кажется, не согласны с моим ответом, однако, я думаю, что они упускают мою точку зрения. Насколько мне известно, нет приложения, которое может взять последовательность исполняемых байтов для одной архитектуры, разложить ее на уровне байт-кода, включая все необходимые вызовы внешних библиотек, включая вызовы ядра базовой ОС, и собрать его для другой системы и сохранить результирующий исполняемый байт-код . Другими словами, нет приложения, которое могло бы взять что-то столь же простое, как Notepad.exe, разложить небольшой файл размером 190 КБ и на 100% собрать его в приложение, которое могло бы работать в Linux или OSX.
Насколько я понимаю, задающий вопрос хотел знать, что если мы можем виртуализировать программное обеспечение или запускать приложения с помощью таких программ, как Wine или Parallels, то почему мы не можем просто повторно перевести байт-код для разных систем. Причина в том, что если вы хотите полностью пересобрать приложение для другой архитектуры, вы должны разложить весь байт-код, необходимый для его запуска, прежде чем собирать его. В каждом приложении есть нечто большее, чем просто исполняемый файл, скажем, для компьютера с Windows. Все приложения Windows используют низкоуровневые объекты и функции ядра Windows для создания меню, текстовых областей, методов изменения размера окна, рисования на дисплее, отправки / получения сообщений ОС и т. Д. И т. Д. И т. Д.
Весь этот байт-код должен быть разобран, если вы хотите повторно собрать приложение и заставить его работать на другой архитектуре.
Такие приложения, как Wine, интерпретируют двоичные файлы Windows на уровне байтов. Они распознают вызовы ядра и переводят эти вызовы либо в связанные функции Linux, либо эмулируют среду Windows. Но это не байт-байт (или код операции для кода операции) ретрансляции. Это скорее перевод из функции в функцию, и это немного отличается.
источник
Кажется, что все эксперты упускают этот момент: «перевод» сложен, но очень подходит для компьютера (не умный, просто трудолюбивый). Но после перевода программы нуждаются в поддержке ОС, например: GetWindowVersion не существует в Linux. Обычно это обеспечивается эмулятором (очень большой). Таким образом, вы могли бы «предварительно перевести» простые программы, но для независимой работы вам нужно создать ссылку на огромную библиотеку. Imaging каждой программы Windows поставляется с собственным kernel.dll + user.dll + shell.dll ...
источник