hello

Is this a MASM bug ?, I was assembling this piece of code:


invoke CreateFile, OFFSET szBuffer, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0
.if eax == INVALID_HANDLE_VALUE
jmp Fin
.else
mov hFile, eax
.endif

Fin:
invoke ExitProcess, 0


the ollydbg output is this


00401036 . 6A 00 PUSH 0 ; /hTemplateFile = NULL
00401038 . 68 80000000 PUSH 80 ; |Attributes = NORMAL
0040103D . 6A 03 PUSH 3 ; |Mode = OPEN_EXISTING
0040103F . 6A 00 PUSH 0 ; |pSecurity = NULL
00401041 . 6A 01 PUSH 1 ; |ShareMode = FILE_SHARE_READ
00401043 . 68 00000080 PUSH 80000000 ; |Access = GENERIC_READ
00401048 . 68 28304000 PUSH demo.00403028 ; |FileName = "E:\demo.exe"
0040104D . E8 16000000 CALL <JMP.&kernel32.CreateFileA> ; \CreateFileA
00401052 . 83F8 FF CMP EAX, -1
00401055 . 75 04 JNZ SHORT demo.0040105B
00401057 . EB 07 JMP SHORT demo.00401060
00401059 . EB 05 JMP SHORT demo.00401060
0040105B > A3 1C304000 MOV DWORD PTR DS:[40301C], EAX
00401060 > 6A 00 PUSH 0 ; /ExitCode = 0
00401062 . E8 07000000 CALL <JMP.&kernel32.ExitProcess> ; \ExitProcess


there is 2 "JMP SHORT demo.00401060" - "EB07 and EB05" :confused:
is a masm bug ?

thank you
Posted on 2004-01-08 20:45:21 by Jnrz
Jnrz,
Whenever you have jumps embedded within conditional code executions, you can usually gain efficiency by manually bypassing the cut and dried code generated by compiliers and HLL assemblers. I think the best way to do this one is:


CMP EAX,INVALID_HANDLE_VALUE
JE Fin

MOV [hFile],EAX
Fin:
INVOKE ExitProcess,0

Also .IF/.ELSE/.ENDIF don't generate the more efficient CMOVXX like you can do manually when the opportunity arises.

By the way, you have a rather obnoxious threatening postscript to your posting. Ratch
Posted on 2004-01-08 21:49:08 by Ratch
Not a bug. Just that masm is not smart enough. That's one example that I would definately make use of JXX instead of .if etc.

My suggestion would be that you do not mix .if stuffs with jmps and conditional jumps (Like what you have done).
Posted on 2004-01-08 21:52:55 by roticv
cmp is not optimal,

or eax,eax ; force eflags

jns continue
invoke ExitProcess,0
continue:
mov [hFile],eax
Posted on 2004-01-08 22:06:40 by donkey
.if eax != INVALID_HANDLE_VALUE
mov hFile, eax
.endif

Fin: invoke ExitProcess,0


This is how your code would look if I wrote it.
Either way, its obviously wrong.
After CreateFile, You're going to ExitProcess no matter what happens.

Sure, its always better to be explicit and use pure opcodes and KNOW what the compiler will generate, but theres no reason to stop using .if, just be a little more wise in how you use it. Anyhow, you're worried that the compiler wasted two bytes? Maybe you are being pedantic, the execution of the code will be the same.
Take a look at anything produced by a C or C++ compiler, they waste MOUNTAINS of bytes with nops and int3's all over the place.
Posted on 2004-01-08 22:10:18 by Homer
What you have observed is not a bug but a necessity when you use the .if/.elseif/..../.endif macros. After performing the instructions listed for each case (except after an .else statement which needs to be last), there must be a jump to the instruction immediately following the .endif statement. That would be the normal program flow. The assembler simply cannot analyze those instructions to decipher if that jump is really necessary.

In your example, the only instruction for the .if case was a jump to the instruction immediately following the .endif statement, explaining why you see two of them. The assembler is not designed to read the programmers mind.

Raymond
Posted on 2004-01-08 22:18:59 by Raymond
that part of the code was just an example, which is not the complete program obviously.
I?ll use normal conditional jumps
thank you everyone :alright:
Posted on 2004-01-08 22:33:19 by Jnrz
donkey,
or eax,eax ; force eflags

jns continue
invoke ExitProcess,0
continue:
mov [hFile],eax


OR EAX,EAX is not optimal. Unless the CPU has smarts, the register needs to be written into. TEST EAX,EAX does the bit check without the write. Ratch
Posted on 2004-01-08 23:19:18 by Ratch

donkey,
or eax,eax ; force eflags

jns continue
invoke ExitProcess,0
continue:
mov [hFile],eax


OR EAX,EAX is not optimal. Unless the CPU has smarts, the register needs to be written into. TEST EAX,EAX does the bit check without the write. Ratch


I have not seen any indication that it is slower, While OR is pairable in both pipes TEST in some cases is not. Generally I will use OR because it is always paired with the jump (short only), TEST is sometimes not pairable so I don't use it. However in the case above it is pairable but takes the same amount of time as register to register OR. So, OR can never be slower but is sometimes not faster.
Posted on 2004-01-08 23:25:57 by donkey
OR instruction overwrites the value in eax. Compare this with the test instruction whereby the results are not overwritten. Therefore the OR instruction creates a write dependency.

Donkey, which processor are you using? How come there are only 2 pipelines ? :grin:
Posted on 2004-01-09 00:27:40 by roticv
I am currently writing all optimizations with the Pentium MMX in mind, for users of TBPaint I occasionally ask what processor they are using and what language. VB is the predominant language and the PMMX is the predominant processor so I write towards that. I code on a P4M and a P3M (I never code on my main PC or run my programs on it) but I am not writing for myself alone so it would be a little selfish to think that everyone has the money to buy those machines and anyway, on the new machines optimization is moot, it is only on the older ones where it pays.
Posted on 2004-01-09 01:13:51 by donkey

Take a look at anything produced by a C or C++ compiler, they waste MOUNTAINS of bytes with nops and int3's all over the place.

When you see a lot of int3's in your code section generated by a C/C++ compiler, it's usually because it supports function-level linking, edit-and-continue, smart linking... ie, rather than recompiling+linking your entire app, it can just modify the changed parts, even if the function size changed a bit. When not having optimizations on, you can get "some" of the edit-and-continue debugging that VB supports. I turn it off for release executables though.

Jnrz, I'd use the if/elseif/whatever for clarity, and worry about the generated code where performance matters... then again, I use HLL where performance doesn't matter too much :)
Posted on 2004-01-09 06:33:23 by f0dder
mmm, interesting, I always think that masm can have a little of sense at this way, but now I understand what is 'hiden macros', by the way, there are some macros for nasm that do the work for construct like /if/else/wend/etc.... and I dont use, because they will not generate correct code and I like to think a little how is the correct way to generate the jump (also you will take a like standar, and you can read easely), yes this constructs will generate more readable code(in some way) or only suposition?, dunno, my suposition now is that the construct of masm are not much eficient?, then I will use HLL macros for nasm knowing that there is no problem :D because masm dosent optimize this constructs they are only what they are, and the way that I maintain my code readable is more by format.

Have a nice day or night
Posted on 2004-01-09 10:18:16 by rea
btw, bitrake made a macro for masm to implement C-style SWITCH blocks - which also handles the "binary search" way of jumps like just about every C/C++ compiler uses... it's sorta cute :)
Posted on 2004-01-09 10:25:07 by f0dder