Why does a nopl
instruction in an x86 take an operand? Don't nops just do, well, nothing?
nopl 0x0(%rax)
NOPW, NOPL, etc.. are the equivalent do-nothings, but take up word and long-sized bytes. e.g. 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.
It is a one-byte or multi-byte NOP that takes up space in the instruction stream but does not impact machine context, except for the EIP register. The multi-byte form of NOP is available on processors with model encoding: CPUID. 01H.
rax is the 64-bit, "long" size register. It was added in 2003 during the transition to 64-bit processors. eax is the 32-bit, "int" size register. It was added in 1985 during the transition to 32-bit processors with the 80386 CPU.
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With