Что делает NOPL в системе x86?
Какова функция NOPL на машине x86? Кажется, что ничего не делает, но почему это всегда в коде сборки?
- Относительная производительность команды x86 inc vs. add
- Что означает `rep ret`?
- Режимы микросовключения и адресации
- Может ли современное оборудование x86 не хранить один байт в памяти?
- Использует ли xor reg, reg преимущество над mov reg, 0?
- Какова цель инструкции «ПАУЗА» в x86?
- Как определить, была ли assembly .NET построена для x86 или x64?
- Что означают скобки в x86 asm?
NOP
– однобайтная операция «ничего не делать», буквально «без операции». NOPW, NOPL и т. Д. Являются эквивалентными do-nothings, но берут слова и длинные байты.
например
NOP // 1byte opcode NOP // 1byte opcode
эквивалентно
NOPW // 2byte opcode.
Они очень удобны для заполнения вещей, поэтому последовательность кода начинается с определенной границы памяти, занимая несколько байтов пространства инструкций, но фактически ничего не делая.
Единственный эффект NOP на CPU – увеличить IP
/ EIP
на 1. Эквиваленты NOPx будут делать это на 2, 4 и т. Д. …
Согласно блогу Джона Фремлина: Операнды NOP на AMD64 , nopw
, nopl
и т. Д. – это синтаксис gas
, а не синтаксис AT & T.
Ниже приведены кодировки команд, генерируемые gas
для разных nop
‘s из источника gas
для команд длиной от 3 до 15 байтов. Обратите внимание, что некоторые из них такие же, как рекомендованные Intel nop
формы (см. Ниже), но не все. В частности, в более длинном gas
nop
используется несколько (до 5) последовательных 0x66
операндов 0x66
в разных nop
формах, тогда как рекомендуемые nop
формы Intel никогда не используют более одного 0x66
операндов 0x66
в любой рекомендуемой nop
.
nop
из исходного кода для газа 2,30 (переформатировано для удобочитаемости):
/* nopl (%[re]ax) */ static const unsigned char alt_3[] = {0x0f,0x1f,0x00}; /* nopl 0(%[re]ax) */ static const unsigned char alt_4[] = {0x0f,0x1f,0x40,0x00}; /* nopl 0(%[re]ax,%[re]ax,1) */ static const unsigned char alt_5[] = {0x0f,0x1f,0x44,0x00,0x00}; /* nopw 0(%[re]ax,%[re]ax,1) */ static const unsigned char alt_6[] = {0x66,0x0f,0x1f,0x44,0x00,0x00}; /* nopl 0L(%[re]ax) */ static const unsigned char alt_7[] = {0x0f,0x1f,0x80,0x00,0x00,0x00,0x00}; /* nopl 0L(%[re]ax,%[re]ax,1) */ static const unsigned char alt_8[] = {0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; /* nopw 0L(%[re]ax,%[re]ax,1) */ static const unsigned char alt_9[] = {0x66,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; /* nopw %cs:0L(%[re]ax,%[re]ax,1) */ static const unsigned char alt_10[] = {0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; static const unsigned char *const alt_patt[] = { f32_1, f32_2, alt_3, alt_4, alt_5, alt_6, alt_7, alt_8, alt_9, alt_10 };
Intel использует различный синтаксис, и для всех длин команд от 1 до 9 байтов доступно nop
. Существует несколько разных nop
, так как все nop
длиной более двух байтов принимают 1 операнд. 0x90
nop
( 0x90
) является синонимом xchg (e)ax,(e)ax
.
Руководство по программированию Intel® 64 и IA-32, том 2 (2A, 2B и 2C): Справочник по набору инструкций, AZ, ГЛАВА 4: ИНСТРУКЦИЯ ПО УСТАНОВКЕ, MZ перечисляет рекомендуемые формы для разных инструкций:
Table 4-12. Recommended Multi-Byte Sequence of NOP Instruction Length Assembly Byte Sequence 2 bytes 66 NOP 66 90H 3 bytes NOP DWORD ptr [EAX] 0F 1F 00H 4 bytes NOP DWORD ptr [EAX + 00H] 0F 1F 40 00H 5 bytes NOP DWORD ptr [EAX + EAX*1 + 00H] 0F 1F 44 00 00H 6 bytes 66 NOP DWORD ptr [EAX + EAX*1 + 00H] 66 0F 1F 44 00 00H 7 bytes NOP DWORD ptr [EAX + 00000000H] 0F 1F 80 00 00 00 00H 8 bytes NOP DWORD ptr [EAX + EAX*1 + 00000000H] 0F 1F 84 00 00 00 00 00H 9 bytes 66 NOP DWORD ptr [EAX + EAX*1 + 00000000H] 66 0F 1F 84 00 00 00 00 00H
Поэтому в дополнение к этим рекомендациям Intel Intel, есть много других nop
. Помимо выравнивания инструкции к определенной границе памяти, как отмечает Марк B в своем ответе, nop
также очень полезны в самомодифицируемом коде, отладке и обратном проектировании.
Фактически, NOP будет использоваться в коде сборки, когда код должен быть исправлен.
Поскольку размер новых инструкций может отличаться от размера старых, требуется дополнение.
Команда заполнения должна действовать так же, как и NOP, хотя она может занимать несколько байтов.
Причина, по которой мы вставляем более сложную инструкцию, например 66 90, вместо нескольких NOP, – это одна команда, как правило, выполняется быстрее, чем несколько NOP.