I see this instruction in the beginning of several Windows programs.
It's copying a register to itself, so basically, this acts as a nop
.
What's the purpose of this instruction?
3 Answers
Raymond Chen (Microsoft) has a blog post discussing this in detail:
https://devblogs.microsoft.com/oldnewthing/20110921-00/?p=9583
In short, it's a compile time addition applied in order to support run time hot patching, so the function can have the first two bytes overwritten with a JMP instruction to redirect execution to another piece of code.
-
4You should probably add a note about the 5 empty bytes preceding the
mov edi, edi
instruction.– tmr232Commented Oct 3, 2015 at 9:59 -
Why not a real 2-byte NOP like
66 90
? That would be more efficient: no back-end uop needed, no extra latency for EDI (in case that matters), no physical register needed to rename the output. Perhaps it's supposed to be a "signature" that tools can recognize as not naturally occurring except in hotpatch code? Commented Dec 8, 2019 at 16:52 -
2@PeterCordes: Raymond Chen discusses that also devblogs.microsoft.com/oldnewthing/20130102-00/?p=5663 "the decision to use MOV EDI, EDI as the two-byte NOP instruction came after consulting with CPU manufacturers for their recommendations for the best two-byte NOP" Commented Aug 26, 2020 at 20:45
-
2@BenSchwehn: Huh, probably that decision dates back to P5 Pentium days, where a
66
prefix made the instruction take an extra cycle to decode. It's unfortunate for later CPUs from P6 and onward. It's also unfortunate that it has to be a NOP, rather than optionally being a useful instruction like a 2-byte encoding ofpush ebp
for functions that use a frame pointer. (Using thepush r/m32
form with a modrm byte, not the 1-byte short form.) But that's somewhat less simple to handle, and need an alternative to not pessimize functions that don't want to push anything. Commented Aug 26, 2020 at 21:02
It's intended to jump to a specific location, 5 bytes before the mov instruction. From there, you have 5 bytes which are intended to be modified to a long jump to somewhere else in 32-bit memory space. Note that when hot-patching, that 5 bytes jump should be placed first, and then the mov can be replaced. Going the other way, you risk the replaced mov-jmp running first, and jumping to the 5 bytes of whatever happens to be there (it's all nops by default, but you never know).
[addition follows]
Regarding writing the 5 bytes jump - there's also the problem of there is only one instruction that will let you write more than 4 bytes atomically - cmpxchg8b, and that's not an ideal instruction for the purpose. If you write the 0xe9 first and then a dword, then you have a race condition if the 0xe9 is executed before you place the dword. Yet another reason to write the long jump first.
-
-
Right, but in the case of INT3s, you definitely don't want to be running that by accident. Commented Apr 5, 2013 at 20:41
-
And in case the function is already detoured, writing the 4-byte jump target address first will atomically replace whatever
rel32
the previousjmp
had. (Assuming that the dword is 4-byte aligned, which it will be if functions are 8 or 16-byte aligned. It ends at the start of a function.) Commented Dec 8, 2019 at 17:07
courtsey Hotpatching and the Rise of Third-Party Patches presentation at BlackHat USA 2006 by Alexander Sotirov
What Is Hotpatching? Hotpatching is a method for modifying the behavior of an application by modifying its binary code at runtime. It is a common technique with many uses:
• debugging (software breakpoints)
• runtime instrumentation
• hooking Windows API functions
• modifying the execution or adding new functionality to closed-source applications
• deploying software updates without rebooting
• fixing security vulnerabilities
Hotpatches are generated by an automated tool that compares the original and patched binaries. The functions that have changed are included in a file with a .hp.dll extension. When the hotpatch DLL is loaded in a running process, the first instruction of the vulnerable function is replaced with a jump to the hotpatch.
The /hotpatch compiler option ensures that the first instruction of every function is a mov edi, edi instruction that can be safely overwritten by the hotpatch. Older versions of Windows are not compiled with this option and cannot be hotpatched.
mov edi,edi
is not a NOP. In x86-64 it zeroes the top 32 bits ofrdi
. In 32-bit codemov edi,edi
can used as a NOP.