15

Why does a nopl instruction in an x86 take an operand? Don't nops just do, well, nothing?

nopl   0x0(%rax)
phuclv
  • 37,963
  • 15
  • 156
  • 475
RouteMapper
  • 2,484
  • 1
  • 26
  • 45
  • You can "do nothing" with an argument, right? `90 nop` also has arguments, it's really `xchg eax, eax`. – harold Jun 10 '13 at 18:56
  • 1
    I ask because a decompiler I'm using is classifying it as a branch instruction. Any reason why that might be happening? – RouteMapper Jun 10 '13 at 19:00
  • It's sort of like a branch over a small bit of data (the bytes that encode the argument), it's sometimes used for that purpose - to efficiently skip some data that has to be there for some reason (ugly hack IMO but hey..), so you can sort of see it as a branch – harold Jun 10 '13 at 19:04
  • What is the data that has to be there? The operand? – RouteMapper Jun 10 '13 at 19:09
  • It doesn't have to have an operand (as you say, it isn't used anyway), but it does. That's Intels fault. – harold Jun 10 '13 at 19:22
  • So what else could possibly be the data it skips over? – RouteMapper Jun 10 '13 at 19:29
  • 1
    supercat gives an example of what that data is used for sometimes – harold Jun 10 '13 at 19:37
  • There is no `nopl` instruction; it's just multi-byte `nop`, which is called `nopl` by the atrocious AT&T syntax. – Griwes Jun 11 '13 at 23:13
  • It most certainly is an instruction. – RouteMapper Jun 12 '13 at 20:33

2 Answers2

9

Many processors' binary instruction sets have multiple ways of representing functionally-identical instructions. For example, the original ARM instruction set includes instructions to load R0 with any value of the form b << n where b is a value from 0 to 255 and n is an even number from 0 to 24. If one wanted to load R0 with the value 256, one could load the instruction which loads it with 1<<8, or one could use the instruction for 4<<6, 16<<4, or 64<<2. The instructions to load those different values all have different binary encodings, even though all four instructions have the same effect.

The assemblers for some compilers go out of their way to provide means of requesting which of the seemingly-identical instructions a piece of code should use. While this is normally not important, there are times when it may be desirable to avoid using certain byte values within a piece of code, or there may be times when modifications to certain bytes within a piece of code should have a particular effect. For example, eight bits in the aformentioned ARM instructions are used to specify the value of b. If code were to overwrite the b part of one of the above instructions with the value 12, the value loaded into R0 would depend upon which of the original four instructions had been used; it could be 0x0C00, 0x0300, 0x00C0, or 0x0030.

Although assemblers for the 8x86 do not generally make it possible to explicitly distinguish between all possible instruction codings, there may be some contexts where being able to specify what byte values should be included within an instruction may be helpful. For example, one approach to handling exceptions would be to have a routine check, when an exception occurs, whether the instruction at the return address is some particular form of NOP and, if it is, interpret its operand as the address of a data structure holding exception-related information. In practice, most 8x86 languages that support exceptions use other means of handling them, but the aforementioned method would slow down normal function returns by the time required to fetch and execute a long NOP, but would be able to handle exceptional exits relatively efficiently (most languages use a slower approach for handling interrupts in the interest of avoiding the cost of executing the NOP in the no-exception case, but other languages could opt to do things differently).

supercat
  • 77,689
  • 9
  • 166
  • 211
  • 4
    While true, in this case it is more useful in that the operand changes the length of the instruction, as shown by [nrz's answer](http://stackoverflow.com/a/12564044/) in the duplicate link in the comments. – ughoavgfhw Jun 10 '13 at 19:25
  • @ughoavgfhw: If one merely needed an arbitrary NOP of the proper length, one could simply define `nop`, `nop2`, `nop3`, etc. or else have a mnemonic for "generate the fastest n-byte nop sequence" whose argument was the required size. If one merely needed e.g. a 7-byte NOP there would be no need to specify a value to go into four of those bytes. – supercat Nov 19 '14 at 21:53
  • That's exactly what most people do, with macros if the assembler doesn't pre-define mnemonics like that, if they need specific NOP lengths. (Most people only ever use `align` directives, not manual multi-byte NOPs; and if you were going pad instructions manually you'd usually want to make existing instructions longer instead of adding separate NOPs. [What methods can be used to efficiently extend instruction length on modern x86?](https://stackoverflow.com/q/48046814)). So usually you see NOP1 / NOP2 / etc. definitions in C source code for an assembler or JIT, not in asm itself. – Peter Cordes May 17 '21 at 18:36
2

Sometimes I use nops when debugging. If I know how something goes wrong but it requires thousands of breakpoint breaks to discover I write code that tests for it. It may look something like this (C-style code):

if (condition_occurred)
{
  asm("nop");
}

When I set a breakpoint on the "asm" line the debugger will set up a DRx register with the linear (physical) address (corresponding to the virtual address) of the nop. When this location is reached a breakpoint interrupt occurs and you enter the debugger. If you're executing without the debugger the nop will be processed (nothing happens). So here I want an instruction that does exactly nothing and it makes sense that it does (doesn't).


Here is an example of where a "do nothing" nop instruction actually does something ... though indirectly.

See page 8 in this paper and notice the first (top) instruction of the loop in example 3 (which is a development of example 2). Also the footnote at the bottom right of the page.

The author hints that additional nops might speed up the process further.

So nops definitely have their uses.

Olof Forshell
  • 3,169
  • 22
  • 28