I am sorry for my poor english first,i don't know if i can express myself clearly
see the code below
IsEmpty proc dwOffset:DWORD
xor ecx,ecx
cmp byte ptr [dwOffset],0
je @f
inc ecx
@@:
ret
IsEmpty endp
the procedure is to check if a string is empty
0040101A /$ 55 push ebp
0040101B |. 8BEC mov ebp, esp
0040101D |. 33C9 xor ecx, ecx
0040101F |. 807D 08 00 cmp byte ptr [ebp+8], 0
00401023 |. 74 01 je short 00401026
00401025 |. 41 inc ecx
00401026 |> C9 leave
00401027 \. C2 0400 retn 4
we can see the compiler use [ebp+8] as [dwOffset]
but [ebp+8] = dwOffset,so [dwOffset] should equals [[ebp+8]]
we must modify our code like below,then it can work as we want
IsEmpty proc dwOffset:DWORD
xor ecx,ecx
mov eax,dwOffset
mov al,[eax]
cmp al,0
je @f
inc ecx
@@:
ret
IsEmpty endp
0040101A /$ 55 push ebp
0040101B |. 8BEC mov ebp, esp
0040101D |. 33C9 xor ecx, ecx
0040101F |. 8B45 08 mov eax, dword ptr [ebp+8]
00401022 |? 8A00 mov al, byte ptr [eax]
00401024 |? 3C 00 cmp al, 0
00401026 |> 74 01 je short 00401029
00401028 ? 41 inc ecx
00401029 ? C9 leave
0040102A $ C2 0400 retn 4
we can see this time the compiler use [ebp+8] as dwOffset correctly
Why the compiler made a mistake in the first time?
PS:I use MASM32 version 9.00 release
stalker,
Testing if a string is empty or zero length is very easy. You just test the first byte for zero. Something like this.
mov eax, buffer_address ; load the address into a register
cmp BYTE PTR [eax], 0 ; compare the 1st byte with zero
je zero ; if equal to zero jump to label
OH,Hutch
it seems that you haven't understood me
I want to know why the compiler made the mistake
not how to check a string is empty or not
Quote from: stalker on August 10, 2008, 09:51:42 AM
Why the compiler made a mistake in the first time?
It didn't. For indirect memory operands the address must be stored in a register or registers. For 32-bit code the operand can consist of 1 or 2 registers, a scale factor on one of the registers, and a displacement.
To further explain MichaelW's answer, Intel x86-based processors are only capable of accessing memory one step (indirection) at a time. You can't use the contents of a memory location to reference another location in one go. [ebp+8] is one indirection (which is okay), [[ebp+8]] would be two (which is not). To achieve what you want, the code would need to look like this:
mov eax, [ebp+8] ; or mov eax, dwOffset
cmp BYTE PTR [eax], 0
When you define the procedure, dwOffset is effectively equated to [ebp+8]. So by writing [dwOffset], you've actually written [[ebp+8]], which is not possible. MASM simply ignores the extra brackets. Other assemblers behave differently, but this is one of the well known but often overlooked quirks of MASM.
Cheers,
Zooba :U
The first example differs from normal only in that it sets the return value in ECX rather than EAX.
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
include \masm32\include\masm32rt.inc
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
comment * -----------------------------------------------------
Build this template with
"CONSOLE ASSEMBLE AND LINK"
----------------------------------------------------- *
iszero PROTO :DWORD
.code
start:
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
call main
inkey
exit
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
main proc
invoke iszero,1
print str$(ecx),13,10
ret
main endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
iszero proc pstr:DWORD
xor ecx, ecx ; zero ECX
cmp BYTE PTR [ebp+8], 0 ; test if 1st byte is zero
je lbl1 ; if zero return ZERO in ECX
inc ecx ; increment ECX to return 1 if its not
lbl1:
ret
iszero endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end start
00401030 fn_00401030: ; Xref 00401027
00401030 55 push ebp
00401031 8BEC mov ebp,esp
00401033 33C9 xor ecx,ecx
00401035 807D0800 cmp byte ptr [ebp+8],0
00401039 7401 jz loc_0040103C
0040103B 41 inc ecx
0040103C loc_0040103C: ; Xref 00401039
0040103C C9 leave
0040103D C20400 ret 4
Quote from: zooba on August 10, 2008, 12:18:12 PM
Intel x86-based processors are only capable of accessing memory one step (indirection) at a time.
thank you MichaelW,thank you Rooba,thank Hutch(though you seems haven't understood me still,may caused by my poor expression)
thank you all very much
stalker,
I recoded your example for a reason, you mod is not required as a direct memory to immediate comparison is a valid opcode.
You add this,
0040101F |. 8B45 08 mov eax, dword ptr [ebp+8]
00401022 |? 8A00 mov al, byte ptr [eax]
00401024 |? 3C 00 cmp al, 0
When its not needed, you use the original code that only does a memory comparison as its shorter. It does not have a mistake in it.
Also,
Hutch's comment about testing for an empty string is merely telling you that your code could be made simpler and faster by not going through all that trouble. You can also test for an empty string in this manner:
cmp SomeString[0], 0
This is not trying to be critical. When we look at code presented in reference to a question, if we see some simple optimization thing or just a simpler way, we will usually mention it.
For me, it is my "raison de vivre."
-- Paul
(^_^)