Что делает NOPL в системе x86?
Какова функция NOPL в машине x86? Такое ощущение, что он ничего не делает, но почему это всегда в коде сборки?
3 ответа
NOP
является однобайтовой операцией "ничего не делать", буквально "без операции". NOPW, NOPL и т. Д. Являются эквивалентными делами, но занимают слово и байты длинного размера.
например
NOP // 1byte opcode
NOP // 1byte opcode
эквивалентно делать
NOPW // 2byte opcode.
Они очень удобны для дополнения, так что последовательность кода начинается на определенной границе памяти, занимая несколько байтов пространства инструкций, но фактически ничего не делая.
Единственное влияние NOP на процессор заключается в увеличении IP
/EIP
на 1. Эквиваленты NOPx будут делать это на 2, 4 и т. д.
Согласно блогу Джона Фремлина: Операнды на NOP на AMD64, nopw
, nopl
и т. д. gas
синтаксис, а не синтаксис AT&T.
Ниже приведены кодировки команд, сгенерированные gas
для разных nop
из gas
источник для команд длиной от 3 до 15 байт. Обратите внимание, что некоторые из них совпадают с рекомендациями Intel nop
формы (см. ниже), но не все. В частности, в дольше nop
"s gas
использует несколько (до 5) подряд 0x66
префиксы операндов в разных nop
формы, тогда как Intel рекомендует nop
формы никогда не используют более одного 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 использует другой синтаксис, и есть nop
Доступно для всех команд длиной от 1 до 9 байтов. Есть несколько разных nop
х, как все nop
более двух байтов принимают 1 операнд. Один байт nop
(0x90
) является синонимом xchg (e)ax,(e)ax
,
Руководство разработчика программного обеспечения для архитектур Intel® 64 и IA-32, том 2 (2A, 2B и 2C): Справочник по наборам инструкций, AZ, ГЛАВА 4: СПРАВОЧНЫЙ НАБОР ИНСТРУКЦИИ, рекомендуются списки MZ nop
формы для инструкций разной длины:
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
Так в дополнение к этим nop
рекомендуется Intel, есть много других nop
тоже. В дополнение к выравниванию инструкции к определенной границе памяти, как Марк Б упоминает в своем ответе, nop
Также очень полезны для самоизменения кода, отладки и обратного инжиниринга.
На самом деле, NOP будет использоваться в коде сборки, когда код должен быть исправлен.
Поскольку размер новых инструкций может отличаться от старых, необходимо заполнение.
Инструкция заполнения должна действовать так же, как NOP, хотя она может занимать несколько байтов.
Причина, по которой мы вставляем более сложную инструкцию, например 66 90, вместо нескольких NOP, состоит в том, что одна команда обычно выполняется быстрее, чем несколько NOP.