Краткий ответ : Вы не можете перевести скомпилированный связанный исполняемый файл. Хотя это технически возможно, это очень маловероятно (см. Ниже). Однако , если у вас есть исходный файл сборки (содержащий инструкции и метки), это очень возможно сделать (хотя, если вы каким-то образом получите исходный код сборки, если программа не написана на сборке, вы должны иметь исходный код программы как ну, так что для начала вам лучше скомпилировать его для другой архитектуры).
Длинный ответ :
QEMU и другие эмуляторы могут переводить инструкции на лету и, следовательно, запускать исполняемый файл на компьютере, для которого он не был скомпилирован. Почему бы не сделать этот перевод заранее, а не на лету, чтобы ускорить процесс?
Я знаю, что это может показаться простым в принципе, но на практике это практически невозможно по нескольким основным причинам. Для начала разные наборы команд используют в значительной степени разные режимы адресации, разные структуры кода операции, разные размеры слов, а в некоторых даже нет нужных вам инструкций.
Допустим, вам нужно заменить инструкцию еще XYZ
двумя инструкциями, ABC
и DEF
. Теперь вы эффективно сместили все относительные / смещенные адреса во всей программе с этого момента, поэтому вам нужно будет проанализировать и пройти всю программу и обновить смещения (как до, так и после изменения). Теперь, скажем, одно из смещений значительно меняется - теперь вам нужно изменить режимы адресации, которые могут изменить размер адреса. Это снова заставит вас пересмотреть весь файл и пересчитать все адреса, и так далее, и так далее.
Когда вы пишете программы на ассемблере, вы можете использовать метки, но процессор не использует - когда файл собран, все метки рассчитываются как относительные, абсолютные или смещенные местоположения. Вы можете понять, почему это быстро становится нетривиальной задачей и почти невозможным. Замена одной инструкции может потребовать, чтобы вы прошли через всю программу сотни раз, прежде чем двигаться дальше.
Исходя из моего немного ограниченного знания сборки, большинство инструкций, таких как MOV, ADD и другие, должны быть переносимы между архитектурами.
Да, но посмотрите на вопросы, которые я изложил выше. Как насчет размера слова машины? Длина адреса? У него вообще есть одинаковые режимы адресации? Опять же, вы не можете просто «найти и заменить» инструкции. Каждый сегмент программы имеет специально определенный адрес. Переходы к другим меткам заменяются литеральными или смещенными адресами памяти при сборке программы.
Все, что не имеет прямого сопоставления, может быть сопоставлено с каким-то другим набором инструкций, так как все машины являются Turing Complete. Будет ли это слишком сложно? Разве это не сработает вообще по какой-то причине, с которой я не знаком? Будет ли это работать, но не даст лучших результатов, чем использование эмулятора?
Вы на 100% правы, что это возможно и будет намного быстрее . Тем не менее, написание программы для достижения этой цели невероятно сложно и невероятно, если не для чего-либо, кроме вопросов, которые я изложил выше.
Если бы у вас был фактический исходный код сборки, было бы тривиально перевести машинный код в другую архитектуру набора команд. Сам машинный код, однако, собирается , поэтому без источника сборки (который содержит различные метки, используемые для вычисления адресов памяти) это становится невероятно трудным. Опять же, изменение одной инструкции может изменить смещения памяти во всей программе и потребовать сотни проходов для пересчета адресов.
Выполнение этого для программы с несколькими тысячами инструкций потребует десятков, если не сотен тысяч проходов. Для относительно небольших программ это может быть возможно, но помните, что количество проходов будет экспоненциально увеличиваться с увеличением количества машинных инструкций в программе. Для любой программы достаточно приличного размера это практически невозможно.