Board index » cppbuilder » help sought, possible asm/cpu/other problem???

help sought, possible asm/cpu/other problem???


2008-07-17 04:42:06 AM
cppbuilder16
(Thanks in advance... Sorry if this seems off-topic to some, but it really
didn't seem non-technical in nature.)
1)Please report if you spot an error in the BytesOK() routine. Its intended
purposes is to scan the nbytes bytes starting at location pAddr, verifying
that all of those bytes have value bval. It does not explicitly clear
direction flag, but CPU pane reports direction flag as clear (see further
below.) If it finds a non-conforming byte, it may generate an int3, and
will return 1.
2)If the code does not have errors to cause functioning as other than
specified, any reasonable guesses as to why it would trip, with the
information in the CPU pane indicating it should not have indicated an
error?
3)All observed paths leading to this routine are protected by a
synchronization object (it could be reached from differing threads
otherwise)
4)It's only been in the last few weeks that I've started to encounter this,
but this code is part of a replacement heap manager, and is not always
active, although it ususally is on my development machine (for the better
part of the past year.)
5)The CPU disassembly pane does seem to correctly reflect the source written
(if(_eax &0x4000) optimized to test ah, $40.)
When this trip occurs (periodically), on two occasions, chasing the stack by
hand, I have found this in the stack as a seeming starting point (to freeing
some memory):
vcl100.@Graphics@TBrush@$bdtr$qqrv:
52006AD0 53 push ebx
(I've only walked the stack by hand twice, so far...)
int BytesOK(unsigned char *pAddr, unsigned char bval, unsigned nbytes)
{
unsigned ui ;
_asm
{
cld
mov al, bval
//apparently ecx is incremented whether or not compare eq or not...
//so our test for non-zero ecx fails.
mov ecx, nbytes
//We'll increment count of bytes, by one (1) - if actual filler
compares
//NE, ecx will be non-zero. If only the extra byte doesn't
compare, then
//ecx should still be zero. ***ASSUMPTION: There will always be at
//least one readable byte beyond any block...
//Probably bad, better find out where zero flag is and test that...
//inc ecx
mov edi, pAddr
repe scasb
lahf
//now, which bit is the zero/equal bit?
} ;
//if(_ECX)
if(!(_EAX & 0x4000)) //0x40 set in AH
{
if(!MM3AdminData.survivalmode)
if(MM3AdminData.callint3onerror) __asm int 3 ;
return 1 ;
}
return 0 ;
}
Mysteriously, BytesOK() routine trips calling int 3, with presented evidence
indicating to me it had no reason to do so. What might be happening?
pAddr == 0x044003e0
bval == 0xff
nbytes == 32
survivalmode == 0
callint3onerror == 1
cpu window shows ...
dump pane all bytes from 0x044003E0 through 0x044003FF as byte value 0xff
(as desired expected)
ZF == 0 (although would have been blown away by two comparisons after the
test ah, $40)
DF == 0
AL == 0xff
ECX == 0x7
EDI == 0x044003F9
code is protected by synchronization object at higher level,
(AsFarAsICanSee) for all paths leading to this point...
XP SP2, intel P4 3.6GHz hyper-threaded
(ACPI\GENUINEINTEL_-_X86_FAMILY_15_MODEL_4\_0) (computer box about 2.5
years old)
 
 

Re:help sought, possible asm/cpu/other problem???

"dhoke" < XXXX@XXXXX.COM >wrote in message
Quote
(Thanks in advance... Sorry if this seems off-topic to some, but it
really didn't seem non-technical in nature.)
This is not a Win32 API issue. This question would have been better
directed to the .language newsgroups instead.
Quote
Please report if you spot an error in the BytesOK() routine.
Why use assembly for that? A simple loop would be easier to manage:
int BytesOK(unsigned char *pAddr, unsigned char bval, unsigned nbytes)
{
for(unsigned ui = 0; i < nbytes; ++i)
{
if( pAddr[ui] != bval )
{
if( !MM3AdminData.survivalmode )
{
if( MM3AdminData.callint3onerror )
__asm int 3 ;
else
return 0;
}
break;
}
}
return 1;
}
Gambit
 

Re:help sought, possible asm/cpu/other problem???

dhoke wrote:
Quote

1)Please report if you spot an error in the BytesOK() routine.
5)The CPU disassembly pane does seem to correctly reflect the source written
(if(_eax &0x4000) optimized to test ah, $40.)

lahf
//now, which bit is the zero/equal bit?
} ;
//if(_ECX)
if(!(_EAX & 0x4000)) //0x40 set in AH
{
I think you are using the wrong constant. LAHF loads the 16 bit flags
register into AH. The zero flag is bit 6 in this register. To compare
using EAX the extended 32 bit register you need to shift your mask,
0x0040 left by 16 bits to give 0x00400000.
HTH
Dennis Cote
 

{smallsort}

Re:help sought, possible asm/cpu/other problem???

Dennis Cote wrote:
Quote
>lahf
>if(!(_EAX & 0x4000)) //0x40 set in AH

I think you are using the wrong constant. LAHF loads the 16 bit flags
register into AH.
That would be hard to do as AH only has 8 bits.
Quote
The zero flag is bit 6 in this register. To compare
Correct.
Quote
using EAX the extended 32 bit register you need to shift your mask,
0x0040 left by 16 bits to give 0x00400000.
Not correct.
AL is bits 0-7 of EAX.
AH is bits 8-15 of EAX ( 0x0100 to 0x8000 )
Bits 16-31 of EAX are not addressable.
The original code is correct for zf.
Though with all the assembly, it would
be clearer to continue with ASM.
mov edi, pAddr
repe scasb
je return0
};//end asm
if(!MM3AdminData.survivalmode)
if(MM3AdminData.callint3onerror) __asm int 3 ;
return 1 ;
return0:
return 0;
 

Re:help sought, possible asm/cpu/other problem???

Remy Lebeau (TeamB) wrote:
Quote
Why use assembly for that? A simple loop would be easier to manage:
It is part of a memory manager, he wants it small and fast.
Quote
int BytesOK(unsigned char *pAddr, unsigned char bval, unsigned nbytes)
{
for(unsigned ui = 0; i < nbytes; ++i)
{
if( pAddr[ui] != bval )
{
if( !MM3AdminData.survivalmode )
{
if( MM3AdminData.callint3onerror )
__asm int 3 ;
else
return 0;
}
break;
}
}
return 1;
}
Your returns are backwards.
sb 1 for fail, 0 for ok.
if/else incorrect.
Quote
int BytesOK(unsigned char *pAddr, unsigned char bval, unsigned nbytes)
{
for(unsigned ui = 0; i < nbytes; ++i)
{
if( pAddr[ui] != bval )
{
if( !MM3AdminData.survivalmode )
{
if( MM3AdminData.callint3onerror )
__asm int 3 ;
}
return 1;
}
}
return 0;
}
 

Re:help sought, possible asm/cpu/other problem???

dhoke wrote:
Quote
(Thanks in advance... Sorry if this seems off-topic to some, but it really
didn't seem non-technical in nature.)
Perhaps the TASM group?
Quote
1)Please report if you spot an error in the BytesOK() routine. Its intended
purposes is to scan the nbytes bytes starting at location pAddr, verifying
that all of those bytes have value bval. It does not explicitly clear
direction flag, but CPU pane reports direction flag as clear (see further
below.)
Well, there's an error to start:
It Does clear the direction flag.
Quote
int BytesOK(unsigned char *pAddr, unsigned char bval, unsigned nbytes)
{
unsigned ui ;
Warning: ui not used
_asm
{
cld
mov al, bval
mov ecx, nbytes
mov edi, pAddr
repe scasb
lahf
//now, which bit is the zero/equal bit?
} ;
//if(_ECX)
if(!(_EAX & 0x4000)) //0x40 set in AH
{
if(!MM3AdminData.survivalmode)
if(MM3AdminData.callint3onerror) __asm int 3 ;
return 1 ;
}
return 0 ;
}
pAddr == 0x044003e0
bval == 0xff
nbytes == 32
dump pane all bytes from 0x044003E0 through 0x044003FF as byte value 0xff
I think you need to look a bit closer.
Quote
ECX == 0x7
There were 7 bytes to go when it failed.
Quote
EDI == 0x044003F9
pAddr == 0x044003e0
0x00000019 = 25
pAddr[25] != bval
might be [24], forget exactly how repe handles edi.
 

Re:help sought, possible asm/cpu/other problem???

"Remy Lebeau (TeamB)" < XXXX@XXXXX.COM >wrote in message
Quote

"dhoke" < XXXX@XXXXX.COM >wrote in message
news:487e5d3c$ XXXX@XXXXX.COM ...

>(Thanks in advance... Sorry if this seems off-topic to some, but it
>really didn't seem non-technical in nature.)

This is not a Win32 API issue. This question would have been better
directed to the .language newsgroups instead.
OK, haven't taken note of that group.
Quote

Why use assembly for that? A simple loop would be easier to manage:

The conditionally compiled version (removed from what I posted) was very
similar to what you've posted, and made the functionality using it in the
heap manager _painfully_ slow to use. The assembly version has made it
almost acceptable.
Quote

Gambit

 

Re:help sought, possible asm/cpu/other problem???

"Bob Gonder" < XXXX@XXXXX.COM >wrote in message
Quote
Remy Lebeau (TeamB) wrote:

>Why use assembly for that? A simple loop would be easier to manage:

It is part of a memory manager, he wants it small and fast.
Correct. And the difference was significant, as I also have a version
similar to what Remy posted.
Quote

Your returns are backwards.
sb 1 for fail, 0 for ok.
if/else incorrect.
Nope, they're what I want. Yes its "backwards" from C convention, but its
terribly convenient to be able to return multiple (non-zero) failures from a
routine, and have a clue as to what part of a routine failed. In this
particular routine, not significant, but its a convention I have in my code.
Just think "shell" programming (not that I've done much of that), or I
suppose even batch/command file is similar...
 

Re:help sought, possible asm/cpu/other problem???

Didn't follow your train of thought, comments below...
"Bob Gonder" < XXXX@XXXXX.COM >wrote in message
Quote
dhoke wrote:

>that all of those bytes have value bval. It does not explicitly clear
>direction flag, but CPU pane reports direction flag as clear (see further
>below.)

Well, there's an error to start:
It Does clear the direction flag.
Which I wanted as that should cause EDI to be incremented, and looked for
when I was searching for possible cause/error, but for some reason
overlooked (I think I was looking in disassembly pane rather than source at
time I checked, somehow missed fact that I had included it.)
Quote

>int BytesOK(unsigned char *pAddr, unsigned char bval, unsigned nbytes)
>{
>unsigned ui ;
Warning: ui not used
yeah, that's for the conditionally compiled slower version I removed after
inserting in the email.
Quote
>_asm
>{
>cld
>mov al, bval
>mov ecx, nbytes
>mov edi, pAddr
>repe scasb
>lahf
>//now, which bit is the zero/equal bit?
>} ;
>//if(_ECX)
>if(!(_EAX & 0x4000)) //0x40 set in AH
>{
>if(!MM3AdminData.survivalmode)
>if(MM3AdminData.callint3onerror) __asm int 3 ;
>return 1 ;
>}
>return 0 ;
>}
>pAddr == 0x044003e0
>bval == 0xff
>nbytes == 32
>dump pane all bytes from 0x044003E0 through 0x044003FF as byte value 0xff

I think you need to look a bit closer.

>ECX == 0x7

There were 7 bytes to go when it failed.
Yes - and the following 7 bytes were all bval (0xff)... as well as the
preceding 25 or so...
Quote

>EDI == 0x044003F9
>pAddr == 0x044003e0
0x00000019 = 25
pAddr[25] != bval
might be [24], forget exactly how repe handles edi.

((char*)pVal + 25) == 0x44003f9
*((char*)pVal + 25) == 0xff (all 32 bytes from 0x44003e0 through 0x44003ff,
which includes 0x44003f9)
I'm not following your train of thought, as pVal[24] and pVal[25] as well as
preceding and following bytes were all bval...
(I think) The routine should _not_ have tripped, calling the int 3, but it
did - even though the circumstances presented by the de{*word*81} indicate to me
it should not have...
Quote


 

Re:help sought, possible asm/cpu/other problem???

Wonder what, if any bearing this could have. I am not running in 64-bit
mode, but my PC was manufactured before December 2005, and the processor
does have EM64T...
from:
jetteroheller.wordpress.com/2007/03/09/whats-the-difference-between-amd64-and-intel-em64t/
"Early Intel CPUs with EM64T lacked LAHF and SAHF instructions supported by
AMD64 until introduction of Pentium 4 G1
step in December 2005. LAHF and SAHF are load and store instructions,
respectively, for certain status flags. These instructions are used for
virtualization and floating-point condition handling."
I do have to wonder if the blurb is referring to the correct instructions???
"dhoke" < XXXX@XXXXX.COM >wrote in message
Quote
_asm
{
lahf
} ;
p.s. There is a borland.public.cppbuilder.language.basm group, which I will
try to remember for future use.
 

Re:help sought, possible asm/cpu/other problem???

Bob Gonder wrote:
Quote

That would be hard to do as AH only has 8 bits.
AL is bits 0-7 of EAX.
AH is bits 8-15 of EAX ( 0x0100 to 0x8000 )
You are correct. My memory must have failed me. I assumed that LAHF
loaded the entire flags register, but it only loads the low byte of the
flags register.
Quote

The original code is correct for zf.
Though with all the assembly, it would
be clearer to continue with ASM.

mov edi, pAddr
repe scasb
je return0
That is true as well.
The only other thing I can think of is that the ES register (used
implicitly by the SCAS instructions) may have a different value than the
DS register for some reason, thus EDI (i.e. pAddr) is not pointing at
the expected memory when the SCAS is executed.
Dennis Cote
 

Re:help sought, possible asm/cpu/other problem???

"dhoke" < XXXX@XXXXX.COM >wrote in message
Quote
(Thanks in advance... Sorry if this seems off-topic to some, but it
really didn't seem non-technical in nature.)

1)Please report if you spot an error in the BytesOK() routine. Its
intended purposes is to scan the nbytes bytes starting at location pAddr,
verifying that all of those bytes have value bval. It does not explicitly
clear direction flag, but CPU pane reports direction flag as clear (see
further below.) If it finds a non-conforming byte, it may generate an
int3, and will return 1.
2)If the code does not have errors to cause functioning as other than
specified, any reasonable guesses as to why it would trip, with the
information in the CPU pane indicating it should not have indicated an
error?
3)All observed paths leading to this routine are protected by a
synchronization object (it could be reached from differing threads
otherwise)
4)It's only been in the last few weeks that I've started to encounter
this, but this code is part of a replacement heap manager, and is not
always active, although it ususally is on my development machine (for the
better part of the past year.)
5)The CPU disassembly pane does seem to correctly reflect the source
written (if(_eax &0x4000) optimized to test ah, $40.)

When this trip occurs (periodically), on two occasions, chasing the stack
by hand, I have found this in the stack as a seeming starting point (to
freeing some memory):
vcl100.@Graphics@TBrush@$bdtr$qqrv:
52006AD0 53 push ebx
(I've only walked the stack by hand twice, so far...)

int BytesOK(unsigned char *pAddr, unsigned char bval, unsigned nbytes)
{
unsigned ui ;
_asm
{
cld
mov al, bval
//apparently ecx is incremented whether or not compare eq or
not...
//so our test for non-zero ecx fails.
mov ecx, nbytes
//We'll increment count of bytes, by one (1) - if actual filler
compares
//NE, ecx will be non-zero. If only the extra byte doesn't
compare, then
//ecx should still be zero. ***ASSUMPTION: There will always be
at
//least one readable byte beyond any block...
//Probably bad, better find out where zero flag is and test
that...
//inc ecx
mov edi, pAddr
repe scasb // I do not think this is checking that ALL the
characters are equal to what is in register al.
Larry
 

Re:help sought, possible asm/cpu/other problem???

dhoke wrote:
Quote
I do have to wonder if the blurb is referring to the correct instructions???
Well, as I posted earlier, it is blindingly easy to replace the lahf with a je
Quote
p.s. There is a borland.public.cppbuilder.language.basm group, which I will
try to remember for future use.
Also b.p.TASM
And if you are looking for fast code,
the fastcode project posts asm in the delphi.basm group.
There I think you will find that repe scasb is slow.
 

Re:help sought, possible asm/cpu/other problem???

Larry Griffiths wrote:
Quote
>mov edi, pAddr

repe scasb // I do not think this is checking that ALL the
characters are equal to what is in register al.
Why?
What do you think it does that isn't intended?
 

Re:help sought, possible asm/cpu/other problem???

I guess I should type in the code and anaylze it. I have not done any
assembler coding in years.
I think I know what he wants though.
I will post back later.
Larry.
"Bob Gonder" < XXXX@XXXXX.COM >wrote in message
Quote
Larry Griffiths wrote:

>>mov edi, pAddr
>
>repe scasb // I do not think this is checking that ALL the
>characters are equal to what is in register al.

Why?
What do you think it does that isn't intended?


 

Re:help sought, possible asm/cpu/other problem???

Look at this and see if it is close to what you want.
##########################################
bool BytesOK( unsigned char *pAddr, unsigned char bval, unsigned nbytes )
{
if( nbytes )
{
_asm
{
cld
mov al, bval // Value to compare
mov ecx, nbytes // Number of bytes to compare
mov edi, pAddr // Address of buffer
repe scasb
jz ItsOK:
}
//if(!MM3AdminData.survivalmode)
// if(MM3AdminData.callint3onerror) __asm int 3 ;
return 0 ;
}
ItsOK:
return 1 ;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ASMButtonClick(TObject *Sender)
{
long BytesOKCount = 0;
long BytesNotOKCount = 0;
unsigned char* Buffer[257] = { "AAB" };
for( int a = 1; a < 10; a++ )
{
if( BytesOK( Buffer[0], 'A', a ) )
{
BytesOKCount++;
}
else
{
BytesNotOKCount++;
}
}
}
##########################################
Larry Griffiths
"dhoke" < XXXX@XXXXX.COM >wrote in message
Quote
(Thanks in advance... Sorry if this seems off-topic to some, but it
really didn't seem non-technical in nature.)

1)Please report if you spot an error in the BytesOK() routine. Its
intended purposes is to scan the nbytes bytes starting at location pAddr,
verifying that all of those bytes have value bval. It does not explicitly
clear direction flag, but CPU pane reports direction flag as clear (see
further below.) If it finds a non-conforming byte, it may generate an
int3, and will return 1.
2)If the code does not have errors to cause functioning as other than
specified, any reasonable guesses as to why it would trip, with the
information in the CPU pane indicating it should not have indicated an
error?
3)All observed paths leading to this routine are protected by a
synchronization object (it could be reached from differing threads
otherwise)
4)It's only been in the last few weeks that I've started to encounter
this, but this code is part of a replacement heap manager, and is not
always active, although it ususally is on my development machine (for the
better part of the past year.)
5)The CPU disassembly pane does seem to correctly reflect the source
written (if(_eax &0x4000) optimized to test ah, $40.)

When this trip occurs (periodically), on two occasions, chasing the stack
by hand, I have found this in the stack as a seeming starting point (to
freeing some memory):
vcl100.@Graphics@TBrush@$bdtr$qqrv:
52006AD0 53 push ebx
(I've only walked the stack by hand twice, so far...)

int BytesOK(unsigned char *pAddr, unsigned char bval, unsigned nbytes)
{
unsigned ui ;
_asm
{
cld
mov al, bval
//apparently ecx is incremented whether or not compare eq or
not...
//so our test for non-zero ecx fails.
mov ecx, nbytes
//We'll increment count of bytes, by one (1) - if actual filler
compares
//NE, ecx will be non-zero. If only the extra byte doesn't
compare, then
//ecx should still be zero. ***ASSUMPTION: There will always be
at
//least one readable byte beyond any block...
//Probably bad, better find out where zero flag is and test
that...
//inc ecx
mov edi, pAddr
repe scasb
lahf
//now, which bit is the zero/equal bit?
} ;
//if(_ECX)
if(!(_EAX & 0x4000)) //0x40 set in AH
{
if(!MM3AdminData.survivalmode)
if(MM3AdminData.callint3onerror) __asm int 3 ;
return 1 ;
}
return 0 ;
}


Mysteriously, BytesOK() routine trips calling int 3, with presented
evidence indicating to me it had no reason to do so. What might be
happening?

pAddr == 0x044003e0
bval == 0xff
nbytes == 32

survivalmode == 0
callint3onerror == 1

cpu window shows ...
dump pane all bytes from 0x044003E0 through 0x044003FF as byte value 0xff
(as desired expected)
ZF == 0 (although would have been blown away by two comparisons after the
test ah, $40)
DF == 0
AL == 0xff
ECX == 0x7
EDI == 0x044003F9

code is protected by synchronization object at higher level,
(AsFarAsICanSee) for all paths leading to this point...

XP SP2, intel P4 3.6GHz hyper-threaded
(ACPI\GENUINEINTEL_-_X86_FAMILY_15_MODEL_4\_0) (computer box about 2.5
years old)