Первоначально я пытался сгенерировать байты для немедленного перемещения в 64-битный регистр. Конкретная операция, которую я хотел, была
mov rdi, 0x1337
Используя https://www.felixcloutier.com/x86/mov, единственными расширенными инструкциями без знака, которые я видел, были
REX.W + B8+ rd io
Это смутило меня, поэтому я создал небольшую программу сборки, чтобы посмотреть, что будет генерировать ассемблер.
global _start
section .text
_start:
mov rdi, 0x1337
syscall
mov rax, 60
xor rdi, rdi
syscall
Пришлось отключить оптимизации, чтобы был переход в 64-битный регистр. Поэтому я скомпилировал с nasm -felf64 -O0 main.asm && ld main.o
и сгенерировал a.out
. Я смотрю на objdump -M intel -d ./a.out
и эту строку
48 bf 37 13 00 00 00 movabs rdi,0x1337
Эта линия совсем не похожа
REX.W + B8+ rd io
мне? Кроме того, после некоторого исследовать я увидел, что команда должна быть 10 байт. Как вы получаете это от REX.W + B8+ rd io
?
@harold В итоге я сделал это, но я просто запутался в кодировке инструкций. REX.W + B8+ rd io
выглядит очень необычно для меня, и я хотел бы это понять.
Вы пропустили objdump -d -w
, чтобы не переносить длинные инструкции, например 10-байтовые mov r64, imm64
. См. также Разница между movq и movabsq в x86-64. (Кстати, вы можете получить это, не отключая оптимизацию NASM с помощью mov rdi, strict qword 0x1337
. См. Почему NASM на Linux меняет регистры в сборке x86_64). Оба эти ответа имеют отношение к пониманию доступных форм MOV и того, как они работают в машинном коде.
B8+ rd
означает, что операнд (регистр) закодирован в младших 3 битах кода операции, а не в байте ModR/M.
Из Руководства разработчика программного обеспечения Intel,
+rb, +rw, +rd, +ro — Indicated the lower 3 bits of the opcode byte is used to encode the register operand without a modR/M byte. The instruction lists the corresponding hexadecimal value of the opcode byte with low 3 bits as 000b. In non-64-bit mode, a register code, from 0 through 7, is added to the hexadecimal value of the opcode byte. In 64-bit mode, indicates the four bit field of REX.b and opcode[2:0] field encodes the register operand of the instruction. “+ro” is applicable only in 64-bit mode.
Похоже, что Intel хотела использовать +ro
для 64-битных операндов, закодированных таким образом, но на самом деле этого не сделала. Не только в лемме mov
, но где угодно, насколько я мог найти. Например, 64-битные push
и pop
могли иметь + ro
, но у них также есть + rd
. А "Indicateг" скорее всего опечатка, в остальном тексте используется настоящее время.
Регистр (e/r)di
имеет номер 7, а B8 + 7 = BF
объясняет код операции.
io
означает непосредственное qword (o для octo, возможно, как в 8 байтах?).
Префикс REX (40 для базового префикса, +8 для установки бита W, опционально +1 для установки бита B для доступа к R8..R15), код операции, байт нет ModR/M и 8-байтовый непосредственный, добавить до 10 байт.
Откуда взялось «40 для базового префикса, +8 для установки бита W»? Как вы узнали, что нужно установить бит W и добавить к нему 8?
@HappyJerry REX.W
в столбце кодирования указывает, что бит W должен быть установлен (имеет смысл: иначе это будет 32-битный mov
), и это бит, который соответствует 8. REX без установленных флагов равен 40, REX с установленным битом W — это 48, которые вы видели.
Таким образом, REX используется для обозначения регистров. А бит W указывает, используете ли вы 32-битный или 64-битный регистр? Если бы я использовал регистр R9, флаг B был бы установлен. И первый байт будет 49. Что касается байта ModR/M, он используется, когда используется операнд памяти. Значит ли это, что используется любая форма r/m64, r/m32 или r/m16, есть вероятность, что используется байт ModR/M. Если r/mX является ячейкой памяти или смещением
@HappyJerry ModR/M также обычно используется для кодирования регистровых операндов, инструкции с кодировкой +rd
, безусловно, составляют меньшинство. Для большинства инструкций требуется байт modR/M.
@HappyJerry: см. Что такое префикс REX в кодировке инструкций? и Как читать нотацию Intel Opcode
@harold: Ха, я никогда не замечал такого использования o
для oct-байт. В другом месте, например. cqo
мнемоника, Intel использует o
для 16-байтового окт-слово.
@PeterCordes Спасибо. Единственное, чего я не вижу по этим ссылкам, так это того, что означает /0
. Например ADD rm/32 imm32
это 81 /0 id
@HappyJerry: см. мой ответ на Как читать нотацию Intel Opcode для части /0
, используя ModRM.r в качестве дополнительных битов кода операции.
@PeterCordes Итак, /0 - это поле reg в байте ModR/M? Другими словами, косая черта может быть от /0 до /7.
Кстати, почему бы и нет
mov edi, 0x1337
? Тот же эффект, меньшее кодирование.