Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. NOPs in disassembly

NOPs in disassembly

Scheduled Pinned Locked Moved C#
questiondebuggingannouncement
8 Posts 5 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • E Offline
    E Offline
    Ekoj Lirpa
    wrote on last edited by
    #1

    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.

    H P 2 Replies Last reply
    0
    • E Ekoj Lirpa

      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.

      H Offline
      H Offline
      Henry Minute
      wrote on last edited by
      #2

      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.”

      E 1 Reply Last reply
      0
      • H Henry Minute

        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.”

        E Offline
        E Offline
        Ekoj Lirpa
        wrote on last edited by
        #3

        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.

        L 2 Replies Last reply
        0
        • E Ekoj Lirpa

          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.

          L Offline
          L Offline
          Lost User
          wrote on last edited by
          #4

          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.

          G 1 Reply Last reply
          0
          • L Lost User

            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.

            G Offline
            G Offline
            GameZelda
            wrote on last edited by
            #5

            The Old new Thing : What are these spurious nop instructions doing in my C# code?[^]

            E 1 Reply Last reply
            0
            • G GameZelda

              The Old new Thing : What are these spurious nop instructions doing in my C# code?[^]

              E Offline
              E Offline
              Ekoj Lirpa
              wrote on last edited by
              #6

              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.

              1 Reply Last reply
              0
              • E Ekoj Lirpa

                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.

                L Offline
                L Offline
                Lost User
                wrote on last edited by
                #7

                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 --

                1 Reply Last reply
                0
                • E Ekoj Lirpa

                  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.

                  P Offline
                  P Offline
                  PIEBALDconsult
                  wrote on last edited by
                  #8

                  "Pay no attention to that man behind the curtain."

                  1 Reply Last reply
                  0
                  Reply
                  • Reply as topic
                  Log in to reply
                  • Oldest to Newest
                  • Newest to Oldest
                  • Most Votes


                  • Login

                  • Don't have an account? Register

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • World
                  • Users
                  • Groups