Многобайтовый NOP x86 и префикс инструкции
Напомним, что архитектура x86 определяет 0x0F 0x1F [mod R/M]
как многобайтовый NOP.
Теперь я смотрю на конкретный случай 8-байтового NOP: у меня есть
0x0F 0x1F 0x84 0x__ 0x__ 0x__ 0x__ 0x__
где последние 5 байтов получили произвольные значения.
Третий байт, [mod R/M]
Расщепление дает:
mod = 10b
: аргументreg1
+ смещение в формате DWORDreg2 = 000b
: (нам все равно)reg1 = 100b
: указывает, что аргумент вместоSIB
байт + смещение в формате DWORD.
Теперь, в качестве конкретного примера, если я возьму
0x0F 0x1F 0x84 0x12 0x34 0x56 0x78 0x9A
у меня есть
SIB = 0x12
displacement = 0x9A785634
: DWORD
Теперь я добавляю 0x66
префикс инструкции, указывающий, что смещение должно быть WORD вместо DWORD:
0x66 0x0F 0x1F 0x84 0x12 0x34 0x56 0x78 0x9A
Я жду 0x78 0x9A
быть "отрезанным" и рассматриваться как новая инструкция. Однако при компиляции и запуске objdump
в полученном исполняемом файле он по-прежнему использует все 4 байта (DWORD) в качестве смещения.
Я неправильно понимаю значение слова "смещение" в этом контексте? Или 0x66
префикс не влияет на многобайтовые инструкции NOP?
1 ответ
66H
Префикс переопределяет размер операнда до 16 бит.
Он не отменяет размер адреса, если вы хотите, чтобы вы использовали 67H
Вот список всех операндов.
F0h = LOCK -- locks memory reads/writes
String prefixes
F3h = REP, REPE
F2h = REPNE
Segment overrides
2Eh = CS
36h = SS
3Eh = DS
26h = ES
64h = FS
65h = GS
Operand override
66h. Changes size of data expected to 16-bit
Address override
67h. Changes size of address expected to 16-bit
Однако лучше не создавать свои собственные инструкции nop, а придерживаться рекомендуемых (многобайтовых) nops.
Согласно AMD рекомендуемые многобайтовые числа следующие:
Таблица 4-9. Рекомендуемая многобайтовая последовательность инструкции NOP
bytes sequence encoding
1 90H NOP
2 66 90H 66 NOP
3 0F 1F 00H NOP DWORD ptr [EAX]
4 0F 1F 40 00H NOP DWORD ptr [EAX + 00H]
5 0F 1F 44 00 00H NOP DWORD ptr [EAX + EAX*1 + 00H]
6 66 0F 1F 44 00 00H NOP DWORD ptr [AX + AX*1 + 00H]
7 0F 1F 80 00 00 00 00H NOP DWORD ptr [EAX + 00000000H]
8 0F 1F 84 00 00 00 00 00H NOP DWORD ptr [AX + AX*1 + 00000000H]
9 66 0F 1F 84 00 00 00 00 00H NOP DWORD ptr [AX + AX*1 + 00000000H]
Intel не возражает против до 3 избыточных префиксов, поэтому nop может иметь до 11 байтов.
10 66 66 0F 1F 84 00 00 00 00 00H NOP DWORD ptr [AX + AX*1 + 00000000H]
11 66 66 66 0F 1F 84 00 00 00 00 00H NOP DWORD ptr [AX + AX*1 + 00000000H]
Конечно, вы также можете исключить nops, добавив префиксы к обычным инструкциям с избыточными префиксами.
например
rep mov reg,reg //one extra byte
или заставить процессор использовать более длинные версии одной и той же инструкции.
test r8d,r8d is one byte longer than: test edx,edx
Инструкции с непосредственными операндами имеют короткие и длинные версии.
and edx,7 //short
and edx,0000007 //long
Большинство ассемблеров будут старательно сокращать все инструкции для вас, поэтому вам придется самостоятельно кодировать более длинные инструкции db
Распределение их в стратегических местах может помочь вам выровнять цели прыжка, не вызывая задержек из-за декодирования или выполнения nop.
Помните, что на большинстве процессоров nop все еще использует ресурсы.