Я делал это много раз и продолжаю делать это. В этом случае, когда ваша основная цель - читать, а не писать ассемблер, я считаю, что это применимо.
Напишите свой дизассемблер. Не для создания следующего величайшего дизассемблера, этот предназначен исключительно для вас. Цель - выучить набор инструкций. Изучаю ли я ассемблер на новой платформе, вспоминая ассемблер для платформы, которую когда-то знал. Начните с нескольких строк кода, например, добавляя регистры и занимаясь пинг-понгом между дизассемблированием двоичного вывода и добавлением все более и более сложных инструкций на стороне ввода, вы:
1) узнать набор инструкций для конкретного процессора
2) изучите нюансы написания кода на ассемблере для указанного процессора, чтобы вы могли покачивать каждый бит кода операции в каждой инструкции.
3) вы изучаете набор инструкций лучше, чем большинство инженеров, которые используют этот набор инструкций для заработка
В вашем случае есть пара проблем, я обычно рекомендую для начала использовать набор инструкций ARM, сегодня поставлено больше продуктов на базе ARM, чем любых других (включая компьютеры x86). Но вероятность того, что вы используете ARM сейчас и не знаете достаточно ассемблера для написания кода запуска или других подпрограмм, зная, что ARM может помочь или не помочь в том, что вы пытаетесь сделать. Вторая и более важная причина использования ARM в первую очередь заключается в том, что длины инструкций имеют фиксированный размер и выровнены. Дизассемблирование инструкций переменной длины, таких как x86, может быть кошмаром для вашего первого проекта, и цель здесь - изучить набор инструкций, а не создавать исследовательский проект. Третий ARM - это хорошо сделанный набор инструкций, регистры созданы равными и не имеют индивидуальных особенностей.
Так что вам нужно будет выяснить, с какого процессора вы хотите начать. Я предлагаю сначала msp430 или ARM, затем ARM или вторую, а затем хаос x86. Независимо от того, какая платформа, любая платформа, которую стоит использовать, имеет таблицы данных или справочные руководства для программистов, свободные от поставщика, которые включают набор инструкций, а также кодирование кодов операций (биты и байты машинного языка). Чтобы узнать, что делает компилятор и как писать код, с которым компилятору не приходится бороться, хорошо знать несколько наборов инструкций и посмотреть, как один и тот же высокоуровневый код реализуется в каждом наборе инструкций с каждым компилятором при каждой оптимизации. настройка. Вы не хотите заниматься оптимизацией своего кода только для того, чтобы обнаружить, что вы сделали его лучше для одного компилятора / платформы, но намного хуже для каждого другого.
О, для дизассемблирования наборов инструкций переменной длины, вместо того, чтобы просто начинать с начала и дизассемблировать каждое четырехбайтовое слово линейно через память, как в случае с ARM, или каждые два байта, например, msp430 (msp430 имеет инструкции переменной длины, но вы все равно можете обойтись происходит линейно через память, если вы начинаете с точек входа из таблицы векторов прерываний). Для переменной длины вы хотите найти точку входа на основе таблицы векторов или информации о том, как загружается процессор, и следовать коду в порядке выполнения. Вы должны полностью декодировать каждую инструкцию, чтобы знать, сколько байтов используется, тогда, если инструкция не является безусловным переходом, предположите, что следующий после этой инструкции байт является другой инструкцией. Вы также должны сохранить все возможные адреса ветвей и предположить, что это адреса начальных байтов для получения дополнительных инструкций. Однажды, когда мне это удалось, я сделал несколько проходов через двоичный файл. Начиная с точки входа, я пометил этот байт как начало инструкции, затем линейно декодировал через память, пока не попал в безусловный переход. Все цели ветвления были помечены как начальные адреса инструкции. Я сделал несколько проходов через двоичный файл, пока не нашел новых целей ветвления. Если в любое время вы найдете, скажем, 3-байтовую инструкцию, но по какой-то причине вы пометили второй байт как начало инструкции, у вас есть проблема. Если код был сгенерирован компилятором высокого уровня, этого не должно происходить, если компилятор не делает что-то плохое, Если в коде написан от руки ассемблер (например, в старой аркадной игре), вполне возможно, что будут условные переходы, которые никогда не могут произойти, например, r0 = 0, за которым следует переход, если не ноль. Возможно, вам придется вручную отредактировать их из двоичного файла, чтобы продолжить. Для ваших непосредственных целей, которые, как я полагаю, будут на x86, я не думаю, что у вас возникнет проблема.
Я рекомендую инструменты gcc, mingw32 - это простой способ использовать инструменты gcc в Windows, если ваша цель x86. Если не mingw32 plus, то msys - отличная платформа для создания кросс-компилятора из источников binutils и gcc (как правило, довольно просто). mingw32 имеет некоторые преимущества перед cygwin, например, значительно более быстрые программы и вы избегаете ада cygwin dll. gcc и binutils позволят вам писать на C или ассемблере и дизассемблировать ваш код, и существует больше веб-страниц, чем вы можете прочитать, показывая вам, как сделать один или все три. Если вы собираетесь делать это с набором инструкций переменной длины, я настоятельно рекомендую вам использовать набор инструментов, который включает дизассемблер. Например, сторонний дизассемблер для x86 будет сложной задачей, поскольку вы никогда не знаете, правильно ли он разобрался. Некоторые из них также зависят от операционной системы, цель состоит в том, чтобы скомпилировать модули в двоичный формат, который содержит инструкции маркировки информации из данных, чтобы дизассемблер мог выполнять более точную работу. Другой вариант для этой основной цели - иметь инструмент, который может компилироваться непосредственно в ассемблер для вашей проверки, а затем надеяться, что при компиляции в двоичный формат он создаст те же инструкции.
Краткий (ладно, чуть короче) ответ на ваш вопрос. Напишите дизассемблер, чтобы изучить набор инструкций. Я бы начал с чего-то РИСКОГО и простого в освоении, например, ARM. Как только вы узнаете, что один набор инструкций, другие становится намного проще подобрать, часто через несколько часов, с помощью третьего набора инструкций вы можете начать писать код почти сразу, используя таблицу данных / справочное руководство по синтаксису. Все процессоры, которые стоит использовать, имеют техническое описание или справочное руководство, в котором инструкции описаны вплоть до битов и байтов кодов операций. Изучите RISC-процессор, такой как ARM, и CISC, такой как x86, в достаточной степени, чтобы почувствовать различия, такие как необходимость проходить через регистры для всего или иметь возможность выполнять операции непосредственно в памяти с меньшим количеством регистров или без них. Три инструкции операнда вместо двух и т. Д. Когда вы настраиваете свой код высокого уровня, скомпилировать для более чем одного процессора и сравнить результат. Самая важная вещь, которую вы узнаете, заключается в том, что независимо от того, насколько хорошо написан высокоуровневый код, качество компилятора и сделанный выбор оптимизации имеют огромное значение для реальных инструкций. Я рекомендую llvm и gcc (с binutils), ни один из них не производитотличный код, но они многоплатформенные и многоцелевые, и оба имеют оптимизаторы. И оба они бесплатны, и вы можете легко создавать кросс-компиляторы из исходных кодов для различных целевых процессоров.