The Intel Software Developer's Manual defines three encodings for the NOP instruction:
NOPNOP r/m16NOP r/m32
Additionally, Intel recommends specific multi-byte NOP encodings for alignment purposes, as shown below:
| 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 |
However, when these instructions are disassembled using Zydis, the decoded output differs slightly:
| Length | Decode Result |
|---|---|
| 2 bytes | nop |
| 3 bytes | nop [rax], eax |
| 4 bytes | nop [rax], eax |
| 5 bytes | nop [rax+rax*1], eax |
| 6 bytes | nop [rax+rax*1], ax |
| 7 bytes | nop [rax], eax |
| 8 bytes | nop [rax+rax*1], eax |
| 9 bytes | nop [rax+rax*1], ax |
This reveals a discrepancy: Zydis sometimes interprets multi-byte NOP sequences as having an additional operand.
Activity
4Hi @mappzor,
On a related note, would it not be better if no action were associated with the fake NOP operands?
For instance, in version 4.1.1, we get the following output.
If we rely solely on the operand metadata, we might think that the instruction will read (R) from the address pointed to by rax.
$ ZydisInfo -64 0f1f00
== [ BASIC ] ============================================================================================
MNEMONIC: nop [ENC: DEFAULT, MAP: 0F, OPC: 0x1F]
LENGTH: 3
SSZ: 64
EOSZ: 32
EASZ: 64
CATEGORY: WIDENOP
ISA-SET: FAT_NOP
ISA-EXT: BASE
EXCEPTIONS: NONE
ATTRIBUTES: HAS_MODRM ACCEPTS_SEGMENT
OPTIMIZED: 0F 19 00
== [ OPERANDS ] ============================================================================================
## TYPE VISIBILITY ACTION ENCODING SIZE NELEM ELEMSZ ELEMTYPE VALUE
-- --------- ---------- ------ ------------ ---- ----- ------ -------- ---------------------------
0 MEMORY EXPLICIT R MODRM_RM 32 1 32 INT TYPE = MEM
SEG = ds
BASE = rax
INDEX = none
SCALE = 0
DISP = 0x0000000000000000
1 REGISTER EXPLICIT R MODRM_REG 32 1 32 INT eax
-- --------- ---------- ------ ------------ ---- ----- ------ -------- ---------------------------
== [ ATT ] ============================================================================================
ABSOLUTE: nop %eax, (%rax)
RELATIVE: nop %eax, (%rax)
== [ INTEL ] ============================================================================================
ABSOLUTE: nop dword ptr ds:[rax], eax
RELATIVE: nop dword ptr ds:[rax], eax
== [ SEGMENTS ] ============================================================================================
0F 1F 00
: :..MODRM
:..OPCODEI agree I'd make more sense. Currently we don't even have an enum value for that but introducing ZYDIS_OPERAND_ACTION_NONE with value of 0 is a trivial change.
Thank you for your answer; that would indeed be a great addition!
On a separate note, do you have a planned release schedule for the upcoming version?
Seems this issue is basically an inverse of #539. We should probably review all nops and handle them in a uniform way, with or without extra operands. Personally I'm not sure which version would be better.