We help IT Professionals succeed at work.

Assembler CMP with Delphi 3

egono
egono asked
on
803 Views
Last Modified: 2010-04-03
I want to compare 2 memory blocks using the following function:

function ByteComp(ptr1,ptr2:pointer;length:integer):boolean;assembler;
asm
push     ds
push     edi
push     esi
mov      ax,ds
mov      ecx,length
les      esi,ptr1      <- error #1
lds      edi,ptr2      <- error #2  
mov      es,ax
repe     cmpsb
xor      ax,ax
test     ecx,ecx
jz       @ende
inc      ax
@ende:
pop   esi
pop   edi
pop   ds
end;

but I cant compile this thing (using Delphi 3.0/NT 4.0).

I tried (should work with the flat memory model)

 [...]
 mov edi,ptr1
 mov esi,ptr2
 [...]

and I get a access violation at the repe ...

btw - does the addr() function include the segment, or is it only the offset ?
Comment
Watch Question

Commented:
Hum, don't know assembler very well. But I guess it is about the memory model. You don't have segment:offset pointers in the 32 bit environment any more, the pointers are all linear.

Slash/d003303

Author

Commented:
hi slash

do you have another (fast) solution to compare 2 memory blocks ?

Author

Commented:
very strange things happens:

function ByteComp(ptr1,ptr2:pointer;length:integer):boolean;assembler;
asm
push     edi
push     esi
cld
mov      ax,ds
mov      ecx,length    <-- ecx=50 - ok
mov      esi,ptr1      <-- Debugger says that esi=35 ??????
mov      edi,ptr2      <-- edi=2 - ok
mov      es,ax
repe     cmpsb
xor      eax,eax
test     ecx,ecx
jz       @ende
inc      eax
@ende:
pop      esi
pop      edi
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
if ByteComp(pointer(1),pointer(2),50) then ShowMessage('TRUE');
end;

ohh I'm very confused ...
Commented:
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION
KE

Commented:
Well, someone posted an answer while I was submitting... it should go for an answer !

Try this one:

function ByteComp(ptr1,ptr2:pointer;length:integer):Integer;assembler;
asm
  push     esi
  push     edi
  mov      esi,ptr1
  mov      edi,ptr2
  mov      ecx,length
  cld
  repe     cmpsb
  mov      eax,ecx
  pop   edi
  pop   esi
end;

Take care that your memoryblocks are of equal size or at least the length is set to the smallest block :-)

The routine returns the number of bytes left to be compared which in some cases could be usefull.


My test routine:

procedure TForm1.Button1Click(Sender: TObject);
Var
  s1,s2: String;
  x : Boolean;
begin
  s1 := 'Hello World';
  s2 := 'Hello Words';
  x := ByteComp( PChar(s1), PChar(s2), Length(s1) ) = 0;
end;


Commented:
Hi again,
Take a good look at the RTL/VCL sourcecode. Lots and lots of really good stuff in there!

/// John

Author

Commented:
ok erajoj,

CompareMem works and if you tell me why (and why my function dont) you get the 150 points.

function ByteComp(ptr1,ptr2:pointer;length:integer):boolean;assembler;
asm
push     edi
push     esi
cld
mov      ax,ds
mov      ecx,length
mov      esi,ptr1
mov      edi,ptr2
mov      es,ax
repe     cmpsb
xor      eax,eax
test     ecx,ecx
jz       @ende
inc      eax
@ende:
pop      esi
pop      edi
end;

meanwhile I get the answer on my own ...

Author

Commented:
Hi KE

sorry erajoj's answer is very good, so I give him the points ...

Author

Commented:
to KE again,

you can make your function a little bit faster :-) ...

Author

Commented:
for all the other boys and girls who buy the answer:

My first try (with les/lds) wouldn't work because we are in a flat memory.

The second one should work, *BUT* delphi does a little bit optimizing on its own (not documented in my version of delphi). It dosnt puts the three parameters on the stack, as it should. The parameters are in the registers (eax=ptr1, edx=ptr2, ecx=length), so my "mov ax,ds" destroyes the first parameter and the function crashs.

thats it (it costs me about 5 hours :-( ) ...

The posted answer includes the optimal way to do the thing I want.

Author

Commented:
erajoj - you have the points (take a look at my comments) ...

Commented:
Hi Again "egono",
Well; your function works, almost, you just mess up EAX (hard bug to detect) and you have to change jz to jnz. See below:

asm
       push     edi
       push     esi
       cld
//       mov      ax,ds    // here's where you mess up EAX that's needed...
       mov      ecx,length
       mov      esi,ptr1 // ...here, see below
       mov      edi,ptr2
// why you do the following two lines, I don't know?!?
//       mov      ax,ds    // has to be done here, but is not needed
       mov      es,ax // not needed at all here
       repe     cmpsb
       xor      eax,eax
       test     ecx,ecx
       jnz      @ende // changed here
       inc      eax
       @ende:
       pop      esi
       pop      edi
end;

Here is your code with some optimising, after studying the disassembly view during debugging in Delphi for the last hour, or so:
(Tip: Set HKEY_CURRENT_USER\Software\Borland\Delphi\3.0\Debugging\EnableCPU = "1" for CPU debugging)

asm
  push     edi
  push     esi
//  cld                // not really needed unless...
//  mov      ax,ds   // why do this at all?
//  mov      ecx,length// not necessary(will be changed to mov ecx,ecx by compiler)
//  mov      esi,ptr1  // could be ,ax (will be changed to mov esi,eax by compiler)
//  mov      edi,ptr2  // could be ,dx (will be changed to mov esi,edx by compiler)
  mov esi,eax
  mov edi,edx
//  mov      es,ax   // not necessary since ds=es
  rep      cmpsb     // repe is replaced by compiler
  mov      eax,1     // Result = True
//  test     ecx,ecx // zf set on ecx = 0
//  jz       @ende   // should be jnz
  jcxz    @ende     // jecxz is replaced by compiler
  dec      eax       // Result = False
  @ende:
  pop      esi
  pop      edi
end;

Hope this helps.
/// John

Commented:
Sorry, didn't see your comment.
If you have other asm-problems, ask them here or mail them to me immediately, and I will try to provide faster answers. One main problem was that I didn't find my 80x86 instruction set reference.
There is a good one at (of course) http://developer.intel.com/design/pentium/manuals/24319101.PDF.
BTW, thanks for the points (can be a lot lower next time)!
/// John

Author

Commented:
the hint with the registry setting is worth all the points - thats what I'm looking for all the time - thx again :-)

Unlock the solution to this question.
Thanks for using Experts Exchange.

Please provide your email to receive a sample view!

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.