Solved

Assembler CMP with Delphi 3

Posted on 1998-07-27
14
676 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 ?
0
Comment
Question by:egono
[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
14 Comments
 
LVL 4

Expert Comment

by:d003303
ID: 1358739
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
0
 
LVL 2

Author Comment

by:egono
ID: 1358740
hi slash

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

0
 
LVL 2

Author Comment

by:egono
ID: 1358741
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 ...
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 4

Accepted Solution

by:
erajoj earned 150 total points
ID: 1358742
Hi,
I love assembler, but why not use: function SysUtils.CompareMem(P1, P2: Pointer; Length: Integer): Boolean; assembler;
I mean, it just sits there and waits for you! :-)

BTW, it looks like this:

function CompareMem(P1, P2: Pointer; Length: Integer): Boolean; assembler;
asm
        PUSH    ESI
        PUSH    EDI
        MOV     ESI,P1
        MOV     EDI,P2
        MOV     EDX,ECX
        XOR     EAX,EAX
        AND     EDX,3
        SHR     ECX,1
        SHR     ECX,1
        REPE    CMPSD
        JNE     @@2
        MOV     ECX,EDX
        REPE    CMPSB
        JNE     @@2
@@1:    INC     EAX
@@2:    POP     EDI
        POP     ESI
end;

/// John
0
 
LVL 3

Expert Comment

by:KE
ID: 1358743
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;


0
 
LVL 4

Expert Comment

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

/// John
0
 
LVL 2

Author Comment

by:egono
ID: 1358745
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 ...
0
 
LVL 2

Author Comment

by:egono
ID: 1358746
Hi KE

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

0
 
LVL 2

Author Comment

by:egono
ID: 1358747
to KE again,

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

0
 
LVL 2

Author Comment

by:egono
ID: 1358748
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.

0
 
LVL 2

Author Comment

by:egono
ID: 1358749
erajoj - you have the points (take a look at my comments) ...
0
 
LVL 4

Expert Comment

by:erajoj
ID: 1358750
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
0
 
LVL 4

Expert Comment

by:erajoj
ID: 1358751
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
0
 
LVL 2

Author Comment

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

0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
firemonkey keyboard covers the controls 1 83
shape, triangle, dbctrlgrid 3 46
Delphi Firemonkey send email on Android 1 82
migrate this code to work on android 1 45
Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…

739 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