what is the function of NOPL in x86 machine? It feels like it doesn't do anything, but why is it always in the assembly code?
NOP
is a one-byte "do nothing" operation, quite literally "no operation". NOPW, NOPL, etc.. are the equivalent do-nothings, but take up word and long-sized bytes.
e.g.
NOP // 1byte opcode
NOP // 1byte opcode
is equivalent to doing
NOPW // 2byte opcode.
They're very handy for padding things out so a code sequence begins on a particular memory boundary, by taking up a few bytes of instruction space, yet not actually doing anything.
NOP's sole effect on the CPU is to increment IP
/EIP
by 1. The NOPx equivalents will do so by 2, 4, etc...
XCHG AX,AX
and XCHG BX,BX
are not identical. The first is the official NOP
and does not cause a data dependency. –
Crocker According to John Fremlin's blog: Operands to NOP on AMD64, nopw
, nopl
etc. are gas
syntax, not AT&T syntax.
Below are instruction encodings generated by gas
for different nop
's from gas
source for instruction lengths from 3 to 15 bytes. Note that some are the same as Intel's recommended nop
forms (see below), but not all. In particular, in longer nop
's gas
uses multiple (up to 5) consecutive 0x66
operand prefixes in different nop
forms, whereas Intel's recommended nop
forms never use more than one 0x66
operand prefix in any single recommended nop
instruction.
nop
encodings from the source code for gas 2.30 (reformatted for readability):
/* 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 uses different syntax, and there are nop
's available for all instruction lengths from 1 to 9 bytes. There are several different nop
's, as all nop
's longer than two bytes accept 1 operand. One-byte nop
(0x90
) is synonymous with xchg (e)ax,(e)ax
.
Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 2 (2A, 2B & 2C): Instruction Set Reference, A-Z, CHAPTER 4: INSTRUCTION SET REFERENCE, M-Z lists recommended nop
forms for different instructions lengths:
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
So in addition to these nop
's recommended by Intel, there are many other nop
's too. In addition to aligning an instruction to a specific memory boundary, as Marc B mentions in his answer, nop
's are also very useful in self-modifying code, debugging and reverse-engineering.
nop
is no longer synonymous with xchg eax,eax
. nop
does not zero out the top 32 bits of eax
, but xchg eax,eax
does. –
Kinder xchg eax,eax
for x86-64, it has to use the 2-byte opcode+modrm encoding (87 C0), because 0x90
doesn't have the side-effect on RAX. But xchg eax, ecx
can still assemble to 0x91
- only 0x90 specifically is taken over by nop
felixcloutier.com/x86/nop. But xchg rax,rax
and xchg ax,ax
can still use REX.W or 66 90 because they have no architectural effect. godbolt.org/z/xn5nKnWT6 –
Keyes Actually, NOP will be used in the assembly code when the code need to be patched.
Because the size of the new instructions may be different to that of the old ones, padding is needed.
The padding instruction should act as the same as NOP, although it may occupy several bytes.
The reason that we insert a more complex instruction, like 66 90, instead of several NOPs, is one instruction generally executes more quickly than several NOPs.
© 2022 - 2024 — McMap. All rights reserved.