Я наткнулся на инструкцию «MOV EAX, moffs32», пытаясь понять x86-64.
Насколько я могу судить, эта инструкция будет закодирована (с moffs32
из 0x12345678
) просто в A1 78 56 34 12
.
Однако, когда я запускаю это через дизассемблер, я получаю мусор:
# objdump -D -b binary -mi386 -Mx86-64 -Mintel file.bin
00000000 <.data>:
0: a1 .byte 0xa1
1: 78 56 js 0x59
3: 34 12 xor al,0x12
То же самое касается ndisasm
:
# ndisasm -b 64 file.bin
00000000 A1 db 0xa1
00000001 7856 js 0x59
00000003 3412 xor al,0x12
Инструкцию я получу обратно только в том случае, если разберу ее для x86, а не x86-64 (ndisasm -b 32
):00000000 A178563412 mov eax,[0x12345678]
Почему это? В таблице указано, что инструкция все-таки действительна для 64бит.
Я чувствую, что мне не хватает чего-то фундаментального, но я не могу понять, что именно.
@Jester Я прочитал это предложение пару раз, но не совсем понял. Теперь становится очень понятно, почему он нормально дизассемблировался для x86 и почему в ответе пользователя 555045 всплывает переопределение размера адреса. Спасибо!
32
в moffs32
описывает только размер операнда, а не размер адреса. Размер адреса по-прежнему составляет 64 бита по умолчанию в 64-битном режиме.
Таким образом, это справедливо в 64-битном режиме, но вам нужно больше байтов для смещения, например:
A1 78 56 34 12 00 00 00 00
Он по-прежнему кодирует mov eax, [0x12345678]
, но теперь в 64-битном режиме. Эта инструкция представляет собой редкий случай кодирования 64-битного постоянного адреса. Вы можете использовать его с 32-битным адресом с переопределением размера адреса:
67 A1 78 56 34 12
Но учтите, что это может быть медленнее из-за зависаний LCP на процессорах Intel, чем 7-байтовое кодирование с использованием обычного кода операции 8b 04 25 78 56 34 12
для mov reg, r/m
с адресом в виде расширенного знаком disp32
.
Очень интересно! Я неправильно прочитал таблицу или на связанной странице есть ошибка? Все ли инструкции с moffs, отличными от moffs64, требуют переопределения размера адреса?
Я думаю, комментарий Джестера ответил на оба этих вопроса. Спасибо!
Вы можете использовать его с 32-битным адресом с переопределением размера адреса: - но это может привести к зависанию LCP на процессорах Intel, если инструкция не поступает из кэша uop. Приводит ли префикс изменения длины (LCP) к остановке простой инструкции x86_64? (@NyxCode). Поэтому обычно, если вы хотите использовать 32-битный абсолютный адрес, который может поместиться в расширенный знаком disp32, используйте его вместо этого, даже если это требует дополнительного байта: 8b 04 25 78 56 34 12
используя обычный mov reg, r/m
код операции, который не ограничивается rAX
Обратите внимание, что
moffs32
не означает 32-битное смещение. Это означает смещение к 32-битному операнду (соответствуетeax
). Также прочитайте указанную сноску № 3: «Операнды определяют простое смещение относительно базы сегмента, где 8, 16, 32 и 64 относятся к размеру данных. Атрибут размера адреса инструкции определяет размер смещение: 16, 32 или 64 бита».