Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

Invalid instruction run-time error

Posted on 2004-04-04
2
Medium Priority
?
386 Views
Last Modified: 2008-02-26
In release build only, I get an invalid instruction error on the flagged line:

00401503  push        eax  
00401504  push        offset string "x" (40C128h)
00401509  push        190h
0040150E  push        ebx  
0040150F  call          memmem (401000h)
*00401514  add         esp,10h

memmem being a function written in asm. I can't make head nor tail of this thing. Been working at it for two hours now, just frustrating me. I suspect I might be doing something wrong with the stack, I don't fully understand how it works. Curiosuly, in debug builds memchr produces an error "Access violation reading location 0x00000000", again maybe related to me messing up some of the registers or stack for memchr. Source is as follows:

__declspec(naked) void * __cdecl memmem(const void * buf, size_type count, const void * needle, size_type needle_len)
{
      __asm
      {
            ;//Prologue, preserve registers
            push      ebp
            push    ebx  
            push    esi  
            push    edi

            mov            edi, [esp+14h]                  ;// Put buffer in destination register
            mov            ecx, [esp+18h]                  ;// Put count in ecx register
            mov            esi, [esp+1Ch]                  ;// Put needle in source register
            mov            ebx, [esp+20h]                  ;// Put needle length in ebx register            

            test      ebx, ebx                        ;// Is needle empty?
            jz            found                              ;// Return buffer

            xor            edx, edx                        ;//      Clear edx, because we may use the whole thing later (in to_memchr)

            mov            dl, [esi]                        ;// Put first byte of needle into dl (we know it has atleast 1 byte

            sub            ebx, 2                              ;// Subtract two from needle length (since we have two bytes of it in registers already)
            jb            to_memchr                        ;// Needle length is one byte, call memchr instead

            inc            esi
            mov            dh, [esi]                        ;// Put second byte in dh
            inc            esi

            jmp            main_loop                        ;// Needle is greater than or equal to 2 bytes

main_loop:
            cmp            [edi], dl                        ;// Compare first byte of needle with byte of buffer
            je            get_second_byte                  ;// Match, check the rest of needle against the rest of buffer

            dec            ecx                                    ;// Decrement counter (doesn't set carry flag)
            jz            not_found                        ;// Counter went to zero, needle wasn't found (atleast 2 bytes)

            inc            edi                                    ;// Increment buffer pointer by one byte

            jmp            main_loop                        ;// Back to main loop

get_second_byte:
            dec            ecx                                    ;// Decrement counter (doesn't set carry flag)
            jz            not_found                        ;// Counter went to zero, needle wasn't found (needle is atleast length 2)

            inc            edi                                    ;// Increment buffer pointer
            cmp            [edi], dh                        ;// Check if second byte matches
            je            compare_init                  ;// Match, compare rest of needle against buffer

            jmp            main_loop                        ;// We've fetched the next byte, decremented the counter, just continue on as normal, comparing it with the start of the pattern

compare_init:
            cmp            ecx,ebx                              ;// ebx must be greater than or equal to length of needle - 2
            jb            not_found                        ;// If count is < needle length, needle cannot be in the buffer

            mov            eax, ebx                        ;// Take a new copy of needle length for use as a counter

            push      edi                                    ;// Preserve buffer pointer
            push      esi                                    ;// Preserve needle

            inc            edi

            jmp            compare_loop                  ;// Loop

compare_cleanup:
            pop            esi                                    ;// Restore needle
            pop            edi                                    ;// Restore buffer

            jmp            main_loop                        ;// Continue looking

compare_loop:
            test      eax, eax                        ;// Zero, we're compared this byte already, we've found it!
            jz            found

            cmpsb                                          ;// Compare last characters in each
            jne            compare_cleanup                  ;// No match, keep looking

            dec            eax                                    ;// Decrement counter (checked on next iteration for zero)

            jmp            compare_loop                  ;// So far, so good, keep checking the needle against the buffer

found:
            pop            esi                                    ;// Restore needle
            pop            edi                                    ;// Restore buffer

            dec            edi                                    ;// We're scrolled one ahead (by compare second byte)

            mov            eax, edi                        ;// Return current location in buffer
            jmp            finished

not_found:
            xor            eax, eax                        ;// Return zero
            jmp            finished

to_memchr:
            push      ecx                                    ;// Count
            push      edx                                    ;// Push needle (must be passed as an int)
            push      edi                                    ;// Buffer
            call      memchr                              ;// Call memchr(buffer,value,count)

finished:
            ;// Epilogue
            pop     edi  
            pop     esi  
            pop     ebx  
            pop     ebp  
            ret
      }
}

Thanks,
-Sandra
0
Comment
Question by:Sandra-24
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
2 Comments
 
LVL 3

Accepted Solution

by:
Dancie earned 2000 total points
ID: 10755300
In the part of the code:

to_memchr:
          push     ecx                              ;// Count
          push     edx                              ;// Push needle (must be passed as an int)
          push     edi                              ;// Buffer
          call     memchr                         ;// Call memchr(buffer,value,count)

finished:
          ;// Epilogue
          pop     edi  
          pop     esi  
          pop     ebx  
          pop     ebp  
          ret

Does memchr take care of its own stack  ie. "ret 12" ?
If not then this could be your problem that you push 12 bytes on the stack and are nowhere removed.
Check memchr 's ret instruction if it is not ret 12 then pop the three registers after the call memchr instruction.
like:

to_memchr:
          push     ecx                              ;// Count
          push     edx                              ;// Push needle (must be passed as an int)
          push     edi                              ;// Buffer
          call     memchr                         ;// Call memchr(buffer,value,count)
          pop       edi
          pop       edx
          pop       ecx

finished:
          ;// Epilogue
          pop     edi  
          pop     esi  
          pop     ebx  
          pop     ebp  
          ret
0
 
LVL 3

Author Comment

by:Sandra-24
ID: 10755346
Yes Dancie, that's exactly correct. I just realized that now looking over the docs for __cdecl. I had misunderstood the fact that you have to clean-up the stack as the calling function. I think add  esp, 0Ch is probably more effecient than three pop instructions though. Atleast that's what the compiler does after my code. Not very 64bit compatible perhaps.

Anyway you did give the right answer, thank you very much. Just wish it'd been an hour sooner :) If you want more points, I'm going to create a topic about optimizing the above function.

Thanks,
-Sandra
0

Featured Post

On Demand Webinar - Networking for the Cloud Era

This webinar discusses:
-Common barriers companies experience when moving to the cloud
-How SD-WAN changes the way we look at networks
-Best practices customers should employ moving forward with cloud migration
-What happens behind the scenes of SteelConnect’s one-click button

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The core idea of this article is to make you acquainted with the best way in which you can export Exchange mailbox to PST format.
Want to know how to use Exchange Server Eseutil command? Go through this article as it gives you the know-how.
Visualize your data even better in Access queries. Given a date and a value, this lesson shows how to compare that value with the previous value, calculate the difference, and display a circle if the value is the same, an up triangle if it increased…
In response to a need for security and privacy, and to continue fostering an environment members can turn to for support, solutions, and education, Experts Exchange has created anonymous question capabilities. This new feature is available to our Pr…

722 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question