NOPs in disassembly
-
Hello, this is my first post here, up to now I have only been reading. My question arose from an argument about my habit to write lines like
if( SomeBooleanvariable == true)
{
// do something
}instead of
if( SomeBooleanvariable)
{
// do something
}Granted, it's a bit verbose, but I did not think it would cause the compiler to generate slightly inefficient code. Looking at the disassembly settled the arguement. It generated the same code in both cases. When looking at the disassembly I noticed something else. The compiler had inserted some apparently needless NOP instructions. What are they good for? This was taken from the release build:
if (bValue == true)
00000000 push ebp
00000001 mov ebp,esp
00000003 push ebx
00000004 sub esp,8
00000007 mov dword ptr [ebp-0Ch],ecx
0000000a mov dword ptr [ebp-8],edx
0000000d cmp dword ptr ds:[01BC150Ch],0
00000014 je 0000001B
00000016 call 685A9061
0000001b movzx eax,byte ptr [ebp-8]
0000001f test eax,eax
00000021 je 0000003E
{
m_lFlags = m_lFlags | (long)Flags;
00000023 mov eax,dword ptr [ebp-0Ch]
00000026 mov edx,dword ptr [eax+8]
00000029 mov eax,dword ptr [eax+4]
0000002c or eax,dword ptr [ebp+8]
0000002f or edx,dword ptr [ebp+0Ch]
00000032 mov ecx,dword ptr [ebp-0Ch]
00000035 mov dword ptr [ecx+4],eax
00000038 mov dword ptr [ecx+8],edx
0000003b nop
0000003c jmp 0000005D
}
else
{
m_lFlags = m_lFlags & ~(long)Flags;
0000003e mov eax,dword ptr [ebp+8]
00000041 mov edx,dword ptr [ebp+0Ch]
00000044 not eax
00000046 not edx
00000048 mov ebx,dword ptr [ebp-0Ch]
0000004b and eax,dword ptr [ebx+4]
0000004e and edx,dword ptr [ebx+8]
00000051 mov ecx,dword ptr [ebp-0Ch]
00000054 mov dword ptr [ecx+4],eax
00000057 mov dword ptr [ecx+8],edx
}It has been a while since I really did some assembly on an x86 CPU and I see no immediate use for the NOP at address 0000003b. In the debug build there were more of them, but this one did not disappear in the release build.
-
Hello, this is my first post here, up to now I have only been reading. My question arose from an argument about my habit to write lines like
if( SomeBooleanvariable == true)
{
// do something
}instead of
if( SomeBooleanvariable)
{
// do something
}Granted, it's a bit verbose, but I did not think it would cause the compiler to generate slightly inefficient code. Looking at the disassembly settled the arguement. It generated the same code in both cases. When looking at the disassembly I noticed something else. The compiler had inserted some apparently needless NOP instructions. What are they good for? This was taken from the release build:
if (bValue == true)
00000000 push ebp
00000001 mov ebp,esp
00000003 push ebx
00000004 sub esp,8
00000007 mov dword ptr [ebp-0Ch],ecx
0000000a mov dword ptr [ebp-8],edx
0000000d cmp dword ptr ds:[01BC150Ch],0
00000014 je 0000001B
00000016 call 685A9061
0000001b movzx eax,byte ptr [ebp-8]
0000001f test eax,eax
00000021 je 0000003E
{
m_lFlags = m_lFlags | (long)Flags;
00000023 mov eax,dword ptr [ebp-0Ch]
00000026 mov edx,dword ptr [eax+8]
00000029 mov eax,dword ptr [eax+4]
0000002c or eax,dword ptr [ebp+8]
0000002f or edx,dword ptr [ebp+0Ch]
00000032 mov ecx,dword ptr [ebp-0Ch]
00000035 mov dword ptr [ecx+4],eax
00000038 mov dword ptr [ecx+8],edx
0000003b nop
0000003c jmp 0000005D
}
else
{
m_lFlags = m_lFlags & ~(long)Flags;
0000003e mov eax,dword ptr [ebp+8]
00000041 mov edx,dword ptr [ebp+0Ch]
00000044 not eax
00000046 not edx
00000048 mov ebx,dword ptr [ebp-0Ch]
0000004b and eax,dword ptr [ebx+4]
0000004e and edx,dword ptr [ebx+8]
00000051 mov ecx,dword ptr [ebp-0Ch]
00000054 mov dword ptr [ecx+4],eax
00000057 mov dword ptr [ecx+8],edx
}It has been a while since I really did some assembly on an x86 CPU and I see no immediate use for the NOP at address 0000003b. In the debug build there were more of them, but this one did not disappear in the release build.
The only thing I can think of is that it is for some sort of Word Boundary alignment thingy but I'm probably wrong. :)
Henry Minute Do not read medical books! You could die of a misprint. - Mark Twain Girl: (staring) "Why do you need an icy cucumber?" “I want to report a fraud. The government is lying to us all.”
-
The only thing I can think of is that it is for some sort of Word Boundary alignment thingy but I'm probably wrong. :)
Henry Minute Do not read medical books! You could die of a misprint. - Mark Twain Girl: (staring) "Why do you need an icy cucumber?" “I want to report a fraud. The government is lying to us all.”
Thanks, I thougt of something like this as well, but from the good old days I don't remember any such thing on a x86. Perhaps it's more like getting a pipeline penalty or some other disadvantage when the next instruction is on an odd address. It's just strange that the debug code had several more NOPs, even two in a row at one place.
-
Thanks, I thougt of something like this as well, but from the good old days I don't remember any such thing on a x86. Perhaps it's more like getting a pipeline penalty or some other disadvantage when the next instruction is on an odd address. It's just strange that the debug code had several more NOPs, even two in a row at one place.
-
PreProc wrote:
It's just strange that the debug code had several more NOPs, even two in a row at one place.
I think the compiler adds all sorts of extras in DEBUG code in order to make it easier to stop and single step the code.
-
Thanks, at least some answers, along with many new questions. I guess the times when you had full control over the actual code are long over. It's just that I don't like being less able to predict what the compiler will generate. Even in the good old times it was never a good idea to trust a computer.
-
Thanks, I thougt of something like this as well, but from the good old days I don't remember any such thing on a x86. Perhaps it's more like getting a pipeline penalty or some other disadvantage when the next instruction is on an odd address. It's just strange that the debug code had several more NOPs, even two in a row at one place.
PreProc wrote:
Perhaps it's more like getting a pipeline penalty or some other disadvantage when the next instruction is on an odd address.
There is a penalty when a bitness-changing prefix (edit: just to be clear, a 66 or a 67) is split from an instruction where the ModR/M byte determines whether the length of the instruction is affected by the prefix, by a 16byte boundary (and there are many other penalties but that's the only penalty I can think of that combines regular instructions and addresses)
Last modified: 2hrs 24mins after originally posted --
-
Hello, this is my first post here, up to now I have only been reading. My question arose from an argument about my habit to write lines like
if( SomeBooleanvariable == true)
{
// do something
}instead of
if( SomeBooleanvariable)
{
// do something
}Granted, it's a bit verbose, but I did not think it would cause the compiler to generate slightly inefficient code. Looking at the disassembly settled the arguement. It generated the same code in both cases. When looking at the disassembly I noticed something else. The compiler had inserted some apparently needless NOP instructions. What are they good for? This was taken from the release build:
if (bValue == true)
00000000 push ebp
00000001 mov ebp,esp
00000003 push ebx
00000004 sub esp,8
00000007 mov dword ptr [ebp-0Ch],ecx
0000000a mov dword ptr [ebp-8],edx
0000000d cmp dword ptr ds:[01BC150Ch],0
00000014 je 0000001B
00000016 call 685A9061
0000001b movzx eax,byte ptr [ebp-8]
0000001f test eax,eax
00000021 je 0000003E
{
m_lFlags = m_lFlags | (long)Flags;
00000023 mov eax,dword ptr [ebp-0Ch]
00000026 mov edx,dword ptr [eax+8]
00000029 mov eax,dword ptr [eax+4]
0000002c or eax,dword ptr [ebp+8]
0000002f or edx,dword ptr [ebp+0Ch]
00000032 mov ecx,dword ptr [ebp-0Ch]
00000035 mov dword ptr [ecx+4],eax
00000038 mov dword ptr [ecx+8],edx
0000003b nop
0000003c jmp 0000005D
}
else
{
m_lFlags = m_lFlags & ~(long)Flags;
0000003e mov eax,dword ptr [ebp+8]
00000041 mov edx,dword ptr [ebp+0Ch]
00000044 not eax
00000046 not edx
00000048 mov ebx,dword ptr [ebp-0Ch]
0000004b and eax,dword ptr [ebx+4]
0000004e and edx,dword ptr [ebx+8]
00000051 mov ecx,dword ptr [ebp-0Ch]
00000054 mov dword ptr [ecx+4],eax
00000057 mov dword ptr [ecx+8],edx
}It has been a while since I really did some assembly on an x86 CPU and I see no immediate use for the NOP at address 0000003b. In the debug build there were more of them, but this one did not disappear in the release build.
"Pay no attention to that man behind the curtain."