News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

What is more efficient? [Solved]

Started by lonewolff, March 07, 2009, 03:09:09 AM

Previous topic - Next topic

lonewolff

With 'if' situations what is more efficient?

This


cmp eax,0
je somwhere


or this type of thing?


.IF eax==NULL
do something...
.ENDIF


Or do they both get translated to the same thing (in the same amount of bytes)?

Mark Jones

Generally in this case, they both do the same thing. For general coding, use which ever feels right. However, if this is a speed or size-critical compare, then other manual code should be used. (i.e., CMP is slow and the literal value of 0 is stored as a DWORD in the code, whereas OR eax,eax or TEST eax,eax are faster and smaller, but imply other caveats. One could even check the zero flag if doing an INC or DEC, so many possibilities exist.) See \masm32\help\opcodes.chm.
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

donkey

test eax,eax
jnz somewhere

There is no write operation as with OR so latency and stalls can be avoided. The best way is if you have performed any math on EAX prior to the test to just use the jnz/jz as the flags will be set anyway for example

mov edi,someoffset
@@:
mov [edi],al
dec edi
jnz @B

No need for a test at all.

If you are looking for speed by all means avoid the high level constructs, they are not optimized and will occasionally choose the worst way of comparing data, they also are ripe with unnecessary jumps.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

lonewolff

Thanks for the replies guys.

I am a bit unclear how 'test eax,eax' works.

Wouldn't eax always be equal to eax? Or is something else going on here?

NightWare

 :P here, with test reg,reg, you just fix the flags of the register (its current state), and one of the flags is zero... so why not using it...

donkey

Quote from: lonewolff on March 07, 2009, 04:15:37 AM
Thanks for the replies guys.

I am a bit unclear how 'test eax,eax' works.

Wouldn't eax always be equal to eax? Or is something else going on here?

Hi,

test eax, eax does a logical AND of the register against itself (without the write) and sets the flags, since if the register is any value other than zero ZF will not be set it is a very fast check for FALSE.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

lonewolff

If you logical AND something against itself, wont you always get a result of true? I must be missing something  :red

MichaelW

It's actually a bitwise AND.

0 and 0 = 0
eschew obfuscation

BogdanOntanu

Quote from: lonewolff on March 07, 2009, 04:37:40 AM
If you logical AND something against itself, wont you always get a result of true? I must be missing something  :red

It is not a logical AND. Instead it is a bitwise AND.

IF all bits of the register are zero THEN  the ZERO flag will be set to 1.
IF any bit of the register is 1 THEN the ZERO flag will be set to 0.

In ASM one usually works with bitwise operations. The logical AND/OR/etc operations are the task of the programmer and a matter of convention.
Ambition is a lame excuse for the ones not brave enough to be lazy.
http://www.oby.ro

lonewolff


lonewolff

Just trying a little test. But am unsure of how to use labels to jump from one part of the program to another. This is what I have but cant get it to compile.


.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib

.data
MsgBoxTextTrue db "true",0
MsgBoxTextFalse db "false",0
MsgBoxTitle db "Information",0

.code
start:
mov eax,1
test eax,eax
jnz testprog

invoke ExitProcess,NULL
end start

testprog:
invoke MessageBox,NULL,addr MsgBoxTextTrue,addr MsgBoxTitle,MB_ICONINFORMATION
end testprog

What I am trying to do is experiment with mov eax,1 and move eax,0 to see how the program behaves. But I am not sure of the correct asm usage to jump to 'testprog'.


MichaelW

The END directive marks the end of the source and optionally sets the program entry point. So the first END directive is effectively ending the source, and everything below that point is being ignored, so:

jnz testprog

Is referencing a symbol that has not been defined.

eschew obfuscation

lonewolff

No problems :)

I have used 'ret' instead of end and all is good.

Thanks for your help  :U

MichaelW

For simple tests it's somewhat easier to use the print macro.

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

; ----------------------------------------------------------
; This proc displays the value of the Overflow, Direction,
; Interrupt Enable, Sign, Zero, Auxiliary Carry, Parity, and
; Carry flags, in a DEBUG-style format.
;
;   Flag          position  flag set flag clear
;   ----          --------  -------- ----------
; Overflow        (bit 11)     OV        NV
; Direction       (bit 10)     DN        UP
; Interrupt       (bit 9)      EI        DI
; Sign            (bit 7)      NG        PL
; Zero            (bit 6)      ZR        NZ
; Auxiliary Carry (bit 4)      AC        NA
; Parity          (bit 2)      PE        PO
; Carry           (bit 0)      CY        NC
; ----------------------------------------------------------

dumpflags proc
    pushfd
    pushad
    pushf
    pop   bx
    .IF bx & 1 SHL 11         ; Overflow (bit 11)
      print "OV "
    .ELSE
      print "NV "
    .ENDIF
    .IF bx & 1 SHL 10         ; Direction (bit 10)
      print "DN "
    .ELSE
      print "UP "
    .ENDIF
    .IF bx & 1 SHL 9          ; Interrupt (bit 9)
      print "EI "
    .ELSE
      print "DI "
    .ENDIF
    .IF bx & 1 SHL 7          ; Sign (bit 7)
      print "NG "
    .ELSE
      print "PL "
    .ENDIF
    .IF bx & 1 SHL 6          ; Zero (bit 6)
      print "ZR "
    .ELSE
      print "NZ "
    .ENDIF
    .IF bx & 1 SHL 4          ; Auxiliary Carry (bit 4)
      print "AC "
    .ELSE
      print "NA "
    .ENDIF
    .IF bx & 1 SHL 2          ; Parity (bit 2)
      print "PE "
    .ELSE
      print "PO "
    .ENDIF
    .IF bx & 1 SHL 0          ; Carry (bit 0)
      print "CY ",13,10
    .ELSE
      print "NC ",13,10
    .ENDIF
    popad
    popfd
    ret
dumpflags endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    ;-------------------------------------------------------------
    ; This code uses EBX instead of EAX because EBX, like ESI and
    ; EDI, will retain its value across the print statements.
    ;-------------------------------------------------------------

    mov ebx, 0
    print str$(ebx),13,10
    test ebx, ebx
    call dumpflags

    mov ebx, 1
    print str$(ebx),13,10
    test ebx, ebx
    call dumpflags

    inkey "Press any key to exit..."
    exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start


0
NV UP EI PL ZR NA PE NC
1
NV UP EI PL NZ NA PO NC


eschew obfuscation

jj2007

Here is a simple test case, together with the code you see in OllyDbg. I have chosen a high level construct (".if Zero?") because I am lazy, but I am sure somebody will find a shorter and much faster solution :bg

There is a problem in the documentation: Opcodes.hlp and Opcodes.chm say test "performs a logical AND of the two operands". Well, that's wrong, as several others have stated already.

include \masm32\include\masm32rt.inc

.code
start:
mov eax, 4
mov ecx, 2
test eax, ecx
.if Zero?
nop
print "Is zero"
nop
.else
nop
print "Is not zero"
nop
.endif
nop
exit ; short form of invoke ExitProcess, 0


CPU Disasm
Address               Hex dump                       Command                                                                  Comments
0040100D              ³. B8 04000000                 mov eax, 4
00401012              ³. B9 02000000                 mov ecx, 2
00401017              ³. 85C1                        test ecx, eax
00401019              ³.75 0E                       jne short 00401029
0040101B              ³. 90                          nop
0040101C              ³. 68 00204000                 push offset TESTTEST.00402000                                            ; ÚArg1 = ASCII "Is zero"
00401021              ³. E8 1A000000                 call 00401040                                                            ; ÀTESTTEST.00401040
00401026              ³. 90                          nop
00401027              ³.EB 0C                       jmp short 00401035
00401029              ³> 90                          nop
0040102A              ³. 68 08204000                 push offset TESTTEST.00402008                                            ; ÚArg1 = ASCII "Is not zero"
0040102F              ³. E8 0C000000                 call 00401040                                                            ; ÀTESTTEST.00401040
00401034              ³. 90                          nop
00401035              ³> 90                          nop
00401036              ³. 6A 00                       push 0                                                                   ; ÚExitCode = 0
00401038              ³. E8 B5000000                 call <jmp.&kernel32.ExitProcess>                                         ; ÀKERNEL32.ExitProcess


EDIT: TESTTEST is the name I chose for this proggie. The nops have no specific meaning, but they help Olly to interpret this tiny snippet correctly.