Как обозначаются регистры на машинном языке Intel?

Я изучал машинный язык Intel как в сгенерированном коде, который показан в листинге сборки, так и в дампе самого исполняемого файла, созданного из программы, написанной на MASM. Я не могу понять, как регистры упоминаются в машинных инструкциях. Мой компьютер (и, очевидно, многие другие) имеет 16 регистров, поэтому для ссылки на все из них необходимы 4 бита, от 0 до 15. В качестве примера я посмотрел на инструкцию lea, поскольку она имеет однобайтовый код операции и только один формат. Вот исходный код ассемблера:

    lea     rax, data2
    lea     rcx, data2
    lea     rdx, data2

Data2 находится по смещению 5 в части данных программы. Вот сгенерированный машинный язык:

    488D05FE 1F0000 
    488D0DF7 1F0000
    488D15F0 1F0000

Я знаю, что шестнадцатеричное число 48 обозначает 64-битный регистровый операнд, а 8D - код операции, но остальное все еще остается загадкой. Какой цели служит 1F0000? Это ссылка на место хранения, которое одинаково во всех трех инструкциях? Если это так, то 05FE, 0DF7 и 15F0 должны представлять три регистра, но в какой записи?

Я потратил много времени на чтение https://software.intel.com/en-us/download/intel-64-and-ia-32-architectures-sdm-combined-volumes-1-2a-2b-2c-2d-3a-3b-3c-3d-and-4, но я не считаю это очень полезным. Например, он никогда не нумерует биты и байты, чтобы описать, какие биты инструкции выполняют какую функцию и в соответствии с какой схемой. Он полон деталей, но практически лишен объяснений.

1 ответ

Посмотрим на первую инструкцию: 48 8D 05 FE 1F 00 00

Первый байт: 48h или 0100 1000 b(Я вставляю пробел, чтобы было легче читать). Это байт префикса REX; см. страницу 535 руководства, которое вы связали (он же Том 2A, страница 2-9, но для удобства я буду использовать абсолютные номера страниц). Это определяется тем, что верхние 4 бита0100. Остальные четыре бита называются W, R, X, B соответственно. Таким образом, устанавливается только W, что указывает на 64-битный размер операнда. К остальным мы вернемся позже.

8D это код операции для LEA, Как Вам известно; см. стр. 1149. Поскольку REX.W установлен, он будет хранить эффективный адрес своего второго операнда.m в своем первом операнде r64. Если посмотреть на вторую таблицу на странице 1149, первый операнд закодирован в поле reg байта ModRM, а второй - в поле r/m.

05, или 0000 0101 b, является байтом ModRM. См. Рис. 2-2 на стр. 530. Это объединено с битами из байта префикса REX, как показано на стр. 535, рис. 2-4 (поскольку у нас нет байта SIB). Эта кодировка предназначена для обратной совместимости с 32-битными инструкциями.

  • mod - это два верхних бита байта ModRM: 00 для нас.

  • reg - это следующие три бита: 000. Бит X байта REX прикреплен как старший бит, даваяX.REG = 0.000.

  • r/m - это младшие три бита: 101. Бит B байта REX прикреплен как старший бит, даваяB.R/M = 0.101.

Теперь руководство Intel, кажется, действительно объясняет значение этих полей для 32-битного режима; Я не смог найти там хорошего объяснения случая 64-битного режима. Так что давайте посмотрим в другом месте, например https://wiki.osdev.org/X86-64_Instruction_Encoding.

Значение X.REG объясняется здесь:0.000, для инструкции 64-битного режима, ожидающей регистр общего назначения, RAX.

Для Mod и BR/M см. Эту таблицу. Мод есть00так что смотрим на первый ряд. BR/M =0.101помечен как "[RIP/EIP + disp32]". Это означает, что следующие четыре байта представляют собой 32-битное смещение от указателя инструкции RIP; т.е. смещение от адреса следующей инструкции. См. Стр. 538 руководства Intel. Таким образом, учитываются последние четыре байта, которые образуют 32-битное число с прямым порядком байтов.00001FFEh. Другими словами, операнд памяти1FFEhбайты после адреса следующей инструкции. Предположительно, гдеdata2расположен; ваш ассемблер или компоновщик рассчитал смещение за вас.

Таким образом, первым операндом был RAX, а вторым - [RIP+00001FFEh], поэтому общая инструкция

LEA RAX, [RIP+00001FFEh]

Обратите внимание 1F0000не имело собственного значения; это всего лишь три верхних байта смещения операнда памяти.

Теперь следующий похож: 48 8D 0D F7 1F 00 00. ModRM сейчас00 001 101, так X.REG является 0001, который кодирует RCX. Mod и BR/M снова кодируют RIP+disp32, и теперь смещение00001FF7h. Обратите внимание, что это ровно на 7 меньше, чем в предыдущей инструкции; мы только что выполнили 7-байтовую инструкцию, поэтому RIP увеличился на 7, и поэтому смещение, которое на 7 меньше, указывает точно на то же место, что и раньше, а именноdata2.

Последнее, что вы можете сделать:)

Другие вопросы по тегам