Solved

cmp [esi], [edi] ?

Posted on 2004-04-03
6
2,936 Views
Last Modified: 2012-06-21
The compiler doesn't like the line: cmp [edi], [esi], "bad operand type"

Why?

Also would you have a look at what I'm doing with the compare loop (and the reason I am trying to do the above cmp) and see if you can think of a better way of doing it. Keep in mind this hasn't been run yet so there may be bugs (my first assembly program of > 3 lines :).

void * __cdecl memmem(const void * buf, size_type count, const void * needle, size_type needle_len)
{
      __asm
      {
            pop            ebx                                    ;// Put needle length in ebx register
            pop            edi                                    ;// Put buffer in destination register
            pop            ecx                                    ;// Put count in ecx register
            pop            esi                                    ;// Put needle in source 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, [edi]                        ;// Put first byte of needle into dl (we know it has atleast 1 byte

            cmp            ebx, 2                              ;// Is needle atleast 2 bytes?
            jb            to_memchr                        ;// Needle length is one byte, call memchr instead

            mov            dh, [edi+1]                        ;// Put second byte in dh
            sub            ebx, 2                              ;// Subtract two from needle length (since we have two bytes of it in registers already)

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

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

            jmp            main_loop                        ;// Back to main loop

get_second_byte:
            sub            ecx, 1                              ;// Decrement counter
            jb            not_found                        ;// Counter went below zero, needle wasn't found

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

            jmp            cmp_next_byte                  ;// 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

            jmp            compare_loop                  ;// Loop

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

            jmp            main_loop                        ;// Continue looking

main_loop:
            sub            ecx, 1                              ;// Decrement counter
            jb            not_found                        ;// Counter went below zero, needle wasn't found

            add            edi, 1                              ;// Increment buffer pointer

            jmp            cmp_next_byte                  ;// Compare this byte of the buffer against dl

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

            cmp            [edi], [esi]                  ;// Compare last character
            jne            compare_cleanup                  ;// No match, keep looking

            sub            eax, 1                              ;// Decrement counter (checked on next iteration for zero)
            sub            edi, 1                              ;// Get previous byte
            sub            esi, 1                              ;// Get previous byte

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

found:
            mov            eax, edi                        ;// Return current location in buffer
            ret

not_found:
            xor            eax, eax                        ;// Return zero
            ret

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)
            ret                                           ;// Return memchr's return value
      }
}

Thanks for your time!

This is actually the code of a colleague of mine, I'm just trying to help him get it working, he's an assembly novice also. He's been talking about posting it to code project when it's all finished, so you could look for the final version there later, if you are interested.
0
Comment
Question by:Sandra-24
  • 4
  • 2
6 Comments
 
LVL 11

Accepted Solution

by:
dimitry earned 500 total points
ID: 10750675
You will need to do:
  cmpsb            ;// Compare last character
instead of
  cmp          [edi], [esi]               ;// Compare last character

cmpsb is string operation that compares (in 32-bit variant) ds:[esi] and es:[edi]


0
 
LVL 11

Assisted Solution

by:dimitry
dimitry earned 500 total points
ID: 10750699
As an example the whole memcmp() functions may look like:
   ;
   ;      int memcmp(void  *dst, const void  *src, unsigned length)
   ;
      assume      cs:_TEXT
_memcmp proc      near
      push      bp
      mov      bp,sp
      push      si
      push      di
      push      ds

      mov      cx, [bp+12]
      lds      si, [bp+8]
      les      di, [bp+4]

      xor      ax, ax
.386
      mov      dx, cx
      shr      cx, 2
      rep      cmpsd    ; rep "repeats" cmpsd until cx-- != 0
      jne      diff
      and      dx, 3
      je      equal
      mov      cx, dx
      rep      cmpsb     ; rep "repeats" cmpsb until cx-- != 0
      je      equal
diff:
      inc      ax
equal:
      pop      ds
      pop      di
      pop      si
      pop      bp
      ret
_memcmp endp
0
 
LVL 3

Author Comment

by:Sandra-24
ID: 10750749
Haven't had time to look over it fully yet, but cmpsb looks like the way to go. What's the .386 do? Executes in some sort of compatibility mode or something? Also is there any difference between inc ecx and add ecx, 1? I'll be back later to try and understand your code more fully.

Thanks,
-Sandra
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 11

Expert Comment

by:dimitry
ID: 10750774
I give you this example for your information only. 'cmpsb' itself should help you.
.386 is not a command. It is directive to TASM compiler to use 80386 comamnd set.
inc ecx is shorter in code length and more efficient in cpu clock cycles than add ecx, 1. Result is the same.
0
 
LVL 3

Author Comment

by:Sandra-24
ID: 10750890
Excellent, thanks. I think I can make it from here. If I need any more help I will make a new question.

Just as a matter of curiosity, rep command is a sort of a loop with a counter? Is that more effecient than doing the same with an inc (or dec) command, a cmp, and a jz?

There seems to be several different ways of doing a lot of things in assembly, like to test register eax for zero, you can use, cmp eax,0 with jz or test eax,eax with jz, or or eax,eax with jz (i think). How do you know which is better to use? Is it usually true that fewer/less complex commands = faster code?

Thanks again,
-Sandra
0
 
LVL 11

Expert Comment

by:dimitry
ID: 10752577
rep "converts" any string command to loop until cx-- != 0.
Strings commands are:
  rep movsb, movsw, movsd (move byte, word, dword from ds:[si] to es:[di]) - memcpy in other words
  rep cmpsb, cmpsw, cmpsd (compare byte, word, dword from ds:[si] to es:[di]) - memcmp in other words
There are other commands but those are most useful.
These is also repne that makes "loop" until cx-- !=0 and ZeroFlag == 0. However I suspect that "clever" compiler
will replace rep cmpsb to repne cmpsb automatically.

x86 assembler is pretty "rich" and allows you to do things in different ways. My only recommendation is:
  Write the code in the way you and somebody who will use it may read it. I mean keep it simple.
  For example, despite it may be not 100% efficient, it is much more understandable:
    ; if( AX == 0 ) goto ax_eq_0;
    cmp ax, 0
    je ax_eq_0
 than:
    test ax, ax
    jz ax_eq_0

Good luck !
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Net framework versions 2.0 and sdk 4 508
Mathematics for Computer Science 25 440
How to diplay the real thread ID 21 1,143
Convert dialog units to pixels 5 102
Is your Office 365 signature not working the way you want it to? Are signature updates taking up too much of your time? Let's run through the most common problems that an IT administrator can encounter when dealing with Office 365 email signatures.
Is your company's data protection keeping pace with virtualization? Here are 7 dynamic ways to adapt to rapid breakthroughs in technology.
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…

744 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

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now