Как читать ноту Intel Opcode

Я читаю некоторые материалы о Intel Opcodes инструкции по сборке, но я не могу понять, что это означает, что следует за байтом opcode. Например: "cw", "cd", "/2", "cp", "/3". Пожалуйста, дайте мне подсказку, что это значит или где я могу найти полную ссылку? Заранее спасибо!

E8 cw CALL rel16 Вызов, относительное, смещение относительно следующей инструкции

E8 cd CALL rel32 Вызов около, относительное, смещение относительно следующей инструкции

FF /2 CALL r/m16 Вызов ближний, абсолютный косвенный, адрес указан в r/m16

FF /2 CALL r/m32 Вызов ближний, абсолютный косвенный, адрес указан в r/m32

9A cd CALL ptr16: 16 Вызов далеко, абсолютный, адрес указан в операнде

9A cp CALL ptr16: 32 Вызов далеко, абсолютный, адрес указан в операнде

FF /3 CALL m16: 16 Call дальний, абсолютный косвенный, адрес указан в m16: 16

FF /3 CALL m16: 32 Вызов далеко, абсолютный косвенный адрес, указанный в m16: 32

Ответ 1

Мой любимый источник - это сам Intel: Руководства разработчика программного обеспечения Intel® 64 и IA-32.. И в отличие от прошлых версий, все тома теперь красиво завернуты в один PDF файл (3044).

Похоже, что раздел, который вам больше всего поможет, - 3.1.1.1 в главе 3 тома 2 (стр. 432 из последнего PDF на дату, когда я пишу это).

Ответ 2

3.1.1.1 Столбец опкода в сводной таблице инструкций (инструкции без префикса VEX)

В столбце "Код операции" в приведенной выше таблице показан код объекта, созданный для каждой формы инструкции. Когда это возможно, коды задаются как шестнадцатеричные байты в том же порядке, в котором они появляются в памяти. Определения, отличные от шестнадцатеричных байтов, следующие:

• REX.W - Указывает использование префикса REX, который влияет на размер операнда или семантику команды. Описывается порядок префикса REX и другие необязательные/обязательные префиксы инструкций. Глава 2. Обратите внимание, что REXprefixes, которые поддерживают устаревшие инструкции для 64-битного поведения, явно не указаны в столбце кода операции.

•/digit - Цифра от 0 до 7 указывает, что бит ModR/M команды использует только операнд r/m (регистр памяти). Поле reg содержит цифру, которая предоставляет расширение для кода операции.

•/r - Указывает, что байт ModR/M команды содержит операнд регистров и операнд r/m.

• cb, cw, cd, cp, co, ct - 1-байтовый (cb), 2-байтовый (cw), 4-байтовый (cd), 6-байтовый (cp), 8-байтовое (со) или 10-байтовое (ct) значение после кода операции. Это значение используется для указания смещения кода и, возможно, нового значения для регистрового сегмента кода.

• ib, iw, id, io - 1-байтовый (ib), 2-байтовый (iw), 4-байтовый (id) или 8-байтовый (io) непосредственный операнд инструкция, которая следует за кодом операции, байты ModR/M или байты индексирования шкалы. Код операции определяет, является ли операнд знаковым значением. Все слова, двойные слова и четыре слова задаются с младшим байтом.

• + rb, + rw, + rd, + ro - Указано, что младшие 3 бита байта кода операции используются для кодирования операнда регистра без байта modR/M. Инструкция перечисляет соответствующее шестнадцатеричное значение байта кода операции с низкими 3 битами как 000b. В режиме, отличном от 64-битного, код регистра, от 0 до 7, добавляется к шестнадцатеричному значению байта кода операции. В 64-битном режиме указывает четырехбитное поле поля REX.b и opcode [2: 0], которое кодирует операнд регистров инструкции. "+ ro" применим только в 64-битном режиме. См. Таблицу 3-1 для кодов.

• + я - Число, используемое в инструкциях с плавающей запятой, когда один из операндов является ST (i) из стека регистров FPU. Число я (которое может находиться в диапазоне от 0 до 7) добавляется к шестнадцатеричному байту, указанному слева от знака плюс, чтобы сформировать один байтовый код операции.

3.1.1.3 Столбец команд в Сводной таблице кода операций

В столбце "Инструкция" приведен синтаксис инструкции инструкции, как это было бы в программе ASM386.

Ниже приведен список символов, используемых для представления операндов в инструкциях команд:

• rel8 - Относительный адрес в диапазоне от 128 байт до конца инструкции до 127 байтов после окончания инструкции.

• rel16, rel32 - Относительный адрес в том же сегменте кода, что и собранная команда. Символ rel16 применяется к инструкциям с атрибутом размера операнда 16 бит; символ rel32 применяется к инструкциям с атрибутом размера операнда 32 бита.

• ptr16: 16, ptr16: 32 - Далеко указатель, как правило, на сегмент кода, отличный от кода в инструкции. Обозначение 16:16 указывает, что значение указателя имеет две части. Значение слева от двоеточия - это 16-разрядный селектор или значение, предназначенное для регистра сегмента кода. Значение справа соответствует смещению в целевом сегменте. Символ ptr16: 16 используется, когда атрибут размера операнда инструкции составляет 16 бит; символ ptr16: 32 используется, когда атрибут размера операнда имеет 32 бита.

• r8 - Один из байтовых регистров общего назначения: AL, CL, DL, BL, AH, CH, DH, BH, BPL, SPL, DIL и SIL; или один из байтовых регистров (R8L - R15L), доступных при использовании REX.R и 64-битного режима.

• r16 - Одно из слов регистров общего назначения: AX, CX, DX, BX, SP, BP, SI, DI; или один из регистров слов (R8-R15), доступных при использовании REX.R и 64-битного режима.

• r32 -Один из двухдисковых регистров общего назначения: EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI; или один из регистров двойного слова (R8D - R15D), доступных при использовании REX.R в 64-битном режиме.

• r64 - Один из регистров общего назначения quadword: RAX, RBX, RCX, RDX, RDI, RSI, RBP, RSP, R8-R15. Они доступны при использовании REX.R и 64-битного режима.

• imm8 - Непосредственное значение байта. Символ imm8 - это число, подписанное между -128 и +127 включительно. Для инструкций, в которых imm8 объединен с операндом слова или двойного слова, немедленное значение выставляется в виде слова или двойного слова. Верхний байт слова заполняется самым верхним битом немедленное значение.

• imm16 - Непосредственное значение слова, используемое для инструкций с атрибутом размера операнда - 16 бит. Это число от -32,768 до +32,767 включительно.

• imm32 - Непосредственное значение двойного слова, используемое для инструкций с атрибутом размера операнда 32 бит. Это позволяет использовать число между +2,147,483,647 и -2,147,483,648 включительно.

• imm64 - Непосредственное значение quadword, используемое для инструкций с атрибутом размера операнда 64 бит. Значение позволяет использовать число от +9,223,372,036,854,775,807 и -9,223,372,036,854,775,808 включительно.

• r/m8 - Байт-операнд, являющийся либо содержимым байтового универсального регистра (AL, CL, DL, BL, AH, CH, DH, BH, BPL, SPL, DIL и SIL) или байт из памяти. Байт-регистры R8L-R15L доступны с использованием REX.R в 64-битном режиме.

• r/m16 - Слово универсальный регистр или операнд памяти, используемый для инструкций с атрибутом размера операнда 16 бит. Реестры общего назначения: AX, CX, DX, BX, SP, BP, SI, DI. Содержимое памяти находится по адресу, предоставленному эффективным вычислением адресов. Регистры Word R8W - R15W доступны с использованием REX.R в 64-битном режиме.

• r/m32 - Двойной регистр общего назначения или операнд памяти, используемый для инструкций с атрибутом operandsize 32 бита. Регистры общего назначения с двойным словом: EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI. Содержимое памяти находится по адресу, предоставленному эффективным вычислением адресов. Регистры с двойным словом R8D - R15D доступны при использовании REX.R в 64-битном режиме.

• r/m64 -. Регистр общего назначения с четырьмя словами или операнд памяти, используемый для инструкций с атрибутом размера операнда 64 бит при использовании REX.W. Регистры общего назначения Quadword: RAX, RBX, RCX, RDX, RDI, RSI, RBP, RSP, R8-R15; они доступны только в 64-битном режиме. Содержимое памяти находится по адресу, предоставленному эффективным вычислением адресов.

• m - 16-, 32- или 64-разрядный операнд в памяти.

• m8 - Байт-операнд в памяти, обычно выражаемый как имя переменной или массива, но указываемый регистрами DS: (E) SI или ES: (E) DI. В 64-битном режиме на него указывают регистры RSI или RDI.

• m16 - Текстовый операнд в памяти, обычно выражаемый как имя переменной или массива, но указываемый регистрами DS: (E) SI или ES: (E) DI. Эта номенклатура используется только со строковыми инструкциями.

• m32 - Оператор doubleword в памяти, обычно выражаемый как имя переменной или массива, но указывается регистрами DS: (E) SI или ES: (E) DI. Эта номенклатура используется только со строковыми инструкциями.

• m64 - Опорный операнд памяти в памяти.

• m128 - Одиночный операнд с двойной четверкой памяти в памяти.

• m16: 16, m16: 32 и m16: 64 - Операнд памяти, содержащий дальний указатель, состоящий из двух чисел. Число слева от двоеточия соответствует селектору сегмента указателя. Число справа соответствует его смещению.

• m16 & 32, m16 & 16, m32 & 32, m16 & 64 -Операнд памяти, состоящий из пар элементов данных, размеры которых указаны слева и справа от амперсанда. Разрешены все режимы адресации памяти. Операторы m16 & 16 и m32 & 32 используются инструкцией BOUND для предоставления операнда, содержащего верхнюю и нижнюю границы индексов массива. Оператор m16 & 32 используется LIDT и LGDT, чтобы предоставить слово для загрузки предельного поля и двойное слово для загрузки базового поля соответствующих регистров GDTR и IDTR. Оператор m16 & 64 используется LIDT и LGDT в 64-битном режиме, чтобы предоставить слово для загрузки предельного поля и квадловое слово для загрузки базового поля соответствующих регистров GDTR и IDTR.

• moffs8, moffs16, moffs32, moffs64 - Простая переменная памяти (смещение памяти) типа байта, слова или двойного слова, используемого некоторыми вариантами инструкции MOV. Фактический адрес задается простым смещением относительно базы сегмента. В инструкции не используется байт ModR/M. Число, показанное с помощью moffs, указывает его размер, который определяется атрибутом размера адреса инструкции.

• Sreg - Регистр сегментов. Значения бит сегмента регистров: ES = 0, CS = 1, SS = 2, DS = 3, FS = 4 и GS = 5.

• m32fp, m64fp, m80fp - Оператор с плавающей запятой с одинарной точностью, двойной точностью и двойной расширенной точностью (соответственно). Эти символы обозначают значения с плавающей запятой, которые используются в качестве операндов для инструкций с плавающей запятой x90 FPU.

• m16int, m32int, m64int - Слово, двойное слово и целочисленный квадрат (соответственно) операнда в памяти. Эти символы обозначают целые числа, которые используются в качестве операндов для целых инструкций x87 FPU.

• ST или ST (0) - Верхний элемент стека регистров FPU.

• ST (i) - i-й элемент из верхней части стека регистров FPU (i ← от 0 до 7).

• mm - Регистр MMX. 64-разрядные регистры MMX: от MM0 до MM7.

• mm/m32 - 32 бита младшего порядка регистра MMX или 32-разрядный операнд памяти. 64-разрядные регистры MMX: от MM0 до MM7. Содержимое памяти находится по адресу, предоставленному эффективным вычислением адресов.

• mm/m64 -. Регистр MMX или операнд 64-разрядной памяти. 64-разрядные регистры MMX: от MM0 до MM7. Содержимое памяти находится по адресу, предоставленному эффективным вычислением адресов.

• xmm - Регистр XMM. 128-битные регистры XMM: от XMM0 до XMM7; XMM8-XMM15 доступны с использованием REX.R в 64-разрядном режиме.

• xmm/m32- регистр XMM или операнд 32-разрядной памяти. 128-битные регистры XMM - от XMM0 до XMM7; XMM8-XMM15 доступны с использованием REX.R в 64-битном режиме. Содержимое памяти находится по адресу, предоставленному эффективным вычислением адресов.

• xmm/m64 - Регистр XMM или 64-разрядный операнд памяти. 128-битные SIMD-регистры с плавающей запятой - от XMM0 до XMM7; XMM8-XMM15 доступны с использованием REX.R в 64-битном режиме. Содержимое памяти находится по адресу, предоставленному эффективным вычислением адресов.

• xmm/m128 - Регистр XMM или 128-разрядный операнд памяти. 128-битные регистры XMM - от XMM0 до XMM7; XMM8-XMM15 доступны с использованием REX.R в 64-битном режиме. Содержимое памяти находится по адресу, предоставленному эффективным вычислением адресов.

• - Указывает на подразумеваемое использование регистра XMM0. Когда есть двусмысленность, xmm1 указывает первый операнд источника, используя регистр XMM, а xmm2 - второй операнд источника, используя регистр XMM. Некоторые инструкции используют регистр XMM0 в качестве третьего операнда источника, обозначенного. Использование третьего операнда регистра XMM неявно в кодировке команд и не влияет на кодировку ModR/M.

• ymm - Регистр YMM. 256-битные регистры YMM: YMM0 через YMM7; YMM8 через YMM15 доступны в 64-битном режиме.

• m256 - 32-байтовый операнд в памяти. Эта номенклатура используется только с инструкциями AVX.

• ymm/m256 - Регистр YMM или операнд 256-разрядной памяти.

• - Указывает использование регистра YMM0 как неявный аргумент.

• bnd - 128-битный регистр границ. BND0 через BND3.

• mib - Операнд памяти с использованием формы адреса SIB, где индексный регистр не используется при вычислении адреса, масштаб игнорируется. В эффективном вычислении адресов используются только основание и смещение.

• m512 - 64-байтовый операнд в памяти.

• zmm/m512 - Регистр ZMM или операнд 512 бит.

• {k1} {z} - Реестр масок, используемый в качестве файла сценариев команд. 64-разрядные регистры k: от k1 до k7. Спецификация Writemask доступна исключительно через префикс EVEX. Маскирование может быть выполнено как слияние, где старые значения сохраняются для замаскированных элементов или как маскировка обнуления. Тип маскировки определяется с помощью бита EVEX.z.

• {k1} - Без {z}: регистр маски, используемый как команда writemask для инструкций, которые не позволяют обнулять маскировку, но поддерживают маскирование слияния. Это соответствует инструкциям, требующим, чтобы значение поля aaa отличалось от 0 (например, сбор) и инструкций типа хранилища, которые допускают только маскирование слияния.

• k1 - Реестр масок, используемый в качестве регулярного операнда (как для цели, так и для источника). 64-разрядные регистры k: от k0 до k7.

• mV - операнд векторной памяти; размер операнда зависит от инструкции.

• vm32 {x, y, z} - Векторный массив операндов памяти, указанный с использованием адресации VSIB. Массив адресов памяти задается с использованием общего базового регистра, постоянного масштабного коэффициента и вектора индекса с отдельными элементами 32-разрядного значения индекса в регистре XMM (vm32x), регистра YMM (vm32y) или регистра ZMM (vm32z).

• vm64 {x, y, z} - Векторный массив операндов памяти, указанный с использованием адресации VSIB. Массив адресов памяти задается с использованием общего базового регистра, постоянного масштабного коэффициента и вектора индекса с отдельными элементами с 64-разрядным индексом в регистре XMM (vm64x), регистром YMM (vm64y) или регистром ZMM (vm64z).

• zmm/m512/m32bcst - Операнд, который может быть регистром ZMM, 512-битной ячейкой памяти или 512-битным вектором, загруженным из 32-разрядной ячейки памяти.

• zmm/m512/m64bcst - Операнд, который может быть регистром ZMM, 512-битной ячейкой памяти или 512-битным вектором, загруженным из 64-разрядной ячейки памяти.

- Указывает использование регистра ZMM0 в качестве неявного аргумента.

• {er} - Указывает поддержку встроенного управления округлением, которое применимо только к форме регистра-регистра инструкции. Это также подразумевает поддержку SAE (Подавление всех исключений).

• {sae} - Указывает поддержку SAE (Подавление всех исключений). Это используется для инструкций, которые поддерживают SAE, но не поддерживают встроенное управление округлением.

• SRC1 - Обозначает первый операнд источника в синтаксисе команды инструкции, закодированной префиксом VEX/EVEX и имеющей два или более операндов источника.

• SRC2 - Обозначает второй операнд источника в синтаксисе команды инструкции, закодированной префиксом VEX/EVEX и имеющей два или более операндов источника.

• SRC3 - ​​ Обозначает третий операнд источника в синтаксисе команды инструкции, закодированной с префиксом VEX/EVEX и имеющей три исходных операнда.

• SRC - Источник в команде с одним источником.

• DST - назначение в инструкции. Это поле закодировано reg_field.

Ответ 3

Многие коды операций для немедленных версий команд, включая 83, используют 3-битное поле /r в байте ModR/M в качестве 3 дополнительных битов кода операции. Руководство Intel vol.2 документирует это, и таблица опкодов в приложении включает это, я думаю.

Вот почему большинство оригинальных непосредственных инструкций 8086, таких как and r/m, imm прежнему допускают только 2 операнда, в отличие от shrd eax, edx, 4 или imul edx, [rdi], 12345 где оба поля ModRM используются для кодирования dst/src операнды, а также код операции, подразумевающий непосредственный операнд.

SHRD/SHLD и были добавлены с 386, а imul-немедленное было добавлено с 286. Может быть неудачно, что copy-and-AND (and eax, edx, 0xf) не кодируются, но по крайней мере x86 может использовать LEA для очень распространенного операции копирования и добавления или подоперации.

Но если бы каждая непосредственная и однооперандная инструкция (например, push или not) нуждалась в полном операционном коде для себя, 8086 исчерпал бы 1-байтовые операционные коды. (Особенно потому, что разработчик решил потратить много места для кодирования на коротких формах без байта modrm для AL и AX, таких как cmp ax, 12345 - это всего 3 байта вместо 4 в 16-битном режиме, или cmp eax, imm32 - только 5 байтов вместо 6 для cmp r/m32, imm32 в 32-битном режиме. И для однобайтового регистра xchg-with-ax и однобайтового регистра inc/dec.)


Пример: декодирование 48 83 C4 38. (из того, как один байт кода операции декодирует в различные инструкции в зависимости от поля "регистр/код операции"? Что это?, дубликат этого Q)

48 - это префикс REX.W(REX с установленным только битом W, поэтому он указывает на размер 64-битного операнда, но без старших регистров).

Опкод 83 говорит, что это может быть 7 различных инструкций в зависимости от поля, которое называется "регистр/поле опкода"

Каждая инструкция имеет свои документы, например, add (html extract из руководства vol2), показывает такие кодировки
REX.W + 83/0 ib для ADD r/m64, imm8, что у вас есть.

диаграмма битовых полей ModRM от wiki.osdev.org

  7                           0
+---+---+---+---+---+---+---+---+
|  mod  |    reg    |     rm    |
+---+---+---+---+---+---+---+---+

0xc4 = 0b11000100, так что поле р = 0. Таким образом, наш опкод является 83/0, в Intel нотации.

Остальные поля ModRM:

  • mode = 0b11, поэтому поле rm кодирует операнд регистра, а не базовый регистр для режима адресации.
  • rm = 0b100. рег # 4 = SPL/SP/ESP/RSP. (В этом случае RSP, потому что это 64-битный размер операнда). См. Руководство Intel или https://wiki.osdev.org/X86-64_Instruction_Encoding#Registers для таблиц.

Итак, инструкция add rsp, 0x38

ndisasm -b64 соглашается:

$ cat > foo.asm
db 0x48, 0x83, 0xC4, 0x38
$ nasm foo.asm     # create a flat binary with those bytes, not an object file
$ ndisasm -b64 foo
00000000  4883C438          add rsp,byte +0x38