News:

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

How to generate JA/JNA jump using .IF syntax?

Started by MazeGen, September 22, 2005, 02:37:15 PM

Previous topic - Next topic

MazeGen

Hi all,
I often use .IF-.ELSEIF-.ELSE-.ENDIF blocks, but it seems that this syntax can't generate JA/JNA jumps.
Let's consider JA, Jump if Above, as an example.
We can't use something like .IF !ABOVE?, we can use just flag names (ZERO?, CARRY?, OVERFLOW?, SIGN?, and PARITY?) as an operand. Jump if Above is the same like Jump if Not Below nor Equal (JNBE). If we try to use this condition - .IF !CARRY? || !ZERO? - MASM seems to be unable to recognize that only one jump is necessary and generates two jumps, JAE and JE, what is buggy:


.686
.MODEL FLAT, STDCALL
.LISTALL
.LISTMACROALL

.CODE
Start:

.IF !CARRY? || !ZERO?
   mov eax,ebx
.ENDIF

END Start



.IF !CARRY? || !ZERO?
00000000  73 02    *     jae    @C0002
00000002  74 02    *     je     @C0001
00000004    *@C0002:
00000004  8B C3    mov eax,ebx
.ENDIF
00000006    *@C0001:


BTW, condition !(CARRY? && ZERO?) generates the same code.

So, is there any trick how to force this syntax to generate JA/JNA jumps?

Tedd

I don't think you can do it in the same way as, say, ZERO?
But you could use ".IF (eax < 4)" for example - however, I have a feeling that might produce JGE rather than JAE (signed, rather than unsigned.) But I'm pretty sure there is a way to specifically request unsigned (just don't ask me how :P)
No snowflake in an avalanche feels responsible.

MazeGen

Quote from: Tedd on September 22, 2005, 04:33:14 PM
I don't think you can do it in the same way as, say, ZERO?

I hope some coder knows how to do that...

Quote from: Tedd on September 22, 2005, 04:33:14 PM
But you could use ".IF (eax < 4)" for example -

That's the point. I have a macro for catching internal errors in my program and the error is often signalized only by flag(s), so I can't use such operand in general.

Quote from: Tedd on September 22, 2005, 04:33:14 PM
however, I have a feeling that might produce JGE rather than JAE (signed, rather than unsigned.) But I'm pretty sure there is a way to specifically request unsigned (just don't ask me how :P)

AFAIK .IF uses unsigned compare by default. You can override it, for instance, by using SDWORD PTR eax < 4.

Tedd

The only supported flag tests are:
CARRY?        Carry bit set
OVERFLOW?     Overflow bit set
PARITY?       Parity bit set
SIGN?         Sign bit set
ZERO?         Zero bit set


And if you try to combine two conditions, it will produce two tests, rather than the single one you want.
So it looks like you're stuck with typing them out yourself.
No snowflake in an avalanche feels responsible.

Ratch

MazeGen,

Quote
I often use .IF-.ELSEIF-.ELSE-.ENDIF blocks, but it seems that this syntax can't generate JA/JNA jumps.
Let's consider JA, Jump if Above, as an example.

     Who says that it can't?


                                         .IF EAX <= 3
00000000  83 F8 03    *                     cmp    eax, 003h
00000003  77 04       *                     ja     @C0001
00000005  90                                NOP
00000006  90                                NOP


Quote
We can't use something like .IF !ABOVE?, we can use just flag names (ZERO?, CARRY?, OVERFLOW?, SIGN?, and PARITY?) as an operand. Jump if Above is the same like Jump if Not Below nor Equal (JNBE). If we try to use this condition - .IF !CARRY? || !ZERO? - MASM seems to be unable to recognize that only one jump is necessary and generates two jumps, JAE and JE, what is buggy:

     The code MASM generates for IF !CARRY? || !ZERO?  is not buggy.  It is necessary.  The CF and the ZF are two independent flags, and JAE does not include a test for zero.

Quote
BTW, condition !(CARRY? && ZERO?) generates the same code.

     It should, they are logically equivalent.  See DeMorgan's Rule.

Quote
So, is there any trick how to force this syntax to generate JA/JNA jumps?

     No tricks necessary.  Just code what you want and let MASM take care of the rest.

     If you want a signed comparision, do this.  Ratch


.ELSEIF SDWORD PTR EAX < 3
00000010  EB 23    *     jmp    @C0006
00000012    *@C0004:
00000012  83 F8 03    *     cmp    sdword ptr eax, 003h
00000015  7D 04    *     jge    @C0007
00000017  90    NOP
00000018  90    NOP


Tedd

Ratch, MazeGen's point is that he wants to test for these conditions without necessarily using ".IF (eax <= 3)" but to simply test the flags (having been set previously in the program; possibly even in a separate function) and so would prefer something like ".IF (ABOVE?)"

Quote from: Ratch on September 23, 2005, 02:03:35 PM
The CF and the ZF are two independent flags, and JAE does not include a test for zero.
JA         CF=0 and ZF=0
JAE        CF=0

..obviously MG was refering to JA with the test including zf :wink



The high-level syntax was designed for (and by?) high-level programmers -- who have little reason to test crazy things like that ::)
No snowflake in an avalanche feels responsible.

MazeGen

Quote from: Tedd on September 23, 2005, 02:30:22 PM
Ratch, MazeGen's point is that he wants to test for these conditions without necessarily using ".IF (eax <= 3)" but to simply test the flags (having been set previously in the program; possibly even in a separate function) and so would prefer something like ".IF (ABOVE?)"

Quote from: Ratch on September 23, 2005, 02:03:35 PM
The CF and the ZF are two independent flags, and JAE does not include a test for zero.
JA         CF=0 and ZF=0
JAE        CF=0

..obviously MG was refering to JA with the test including zf :wink

Yeah, you got it.

Quote from: Tedd on September 23, 2005, 02:30:22 PM
The high-level syntax was designed for (and by?) high-level programmers

I've never used anything else than assembly language. I use these syntax because it seems to be more readable for me.
Please don't start a flamewar whether is it really more readable or not, it is just my opinion.

Quote from: Tedd on September 23, 2005, 02:30:22 PM
-- who have little reason to test crazy things like that ::)

:green2

Me, for example :green

MichaelW

If it's just for convenience and code readability you could use a macro, like this for example:

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

    ABOVE macro
        LOCAL rval
        .data
          rval dd 0
        .code
        jna   @F
        mov   rval, 1
      @@:
        EXITM <rval>
    endm
    ABOVE? EQU ABOVE()

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    mov   ebx, 1

    cmp   ebx, 1
    .IF ABOVE?
        print "above",13,10
    .ELSE
        print "not above",13,10
    .ENDIF

    cmp   ebx, 0
    .IF ABOVE?
        print "above",13,10
    .ELSE
        print "not above",13,10
    .ENDIF

    mov   eax, input(13,10,"Press enter to exit...")
    exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start


eschew obfuscation

Ratch

MazeGen,
    Stupid me.  Here I thought you were pointing out a bug in MASM.  My contention is that MASM generates correct code whether you do the comparisons directly, or use flags.  Notice in the snippet below that MASM generates correct code in both cases, but the JA instruction checks BOTH the CF & ZF at the same time, so is therefore shorter.  Ratch


.IF EAX <= 3
00000000  83 F8 03   *    cmp    eax, 003h
00000003  77 02   *    ja     @C0001
00000005  90   NOP
00000006  90   NOP
.ENDIF
00000007   *@C0001:

00000007  83 F8 03 CMP EAX,3
.IF !(!CARRY? && !ZERO?)  ;the logic function has to be inverted to fall through
0000000A  72 02   *    jb     @C0004
0000000C  75 02   *    jne    @C0003
0000000E   *@C0004:
0000000E  90   NOP
0000000F  90   NOP
.ENDIF
00000010   *@C0003:



     Question to moderator.  Why does the (code)(/code) sequence mess up the display of a MASM listing so badly?

     Here is the code without assembly.

.IF EAX <= 3
   NOP
   NOP
.ENDIF

CMP EAX,3
.IF !(!CARRY? && !ZERO?)  ;the logic function has to be inverted to fall through
   NOP
   NOP
.ENDIF

Ratch


sluggy

Quote from: Ratch on September 23, 2005, 09:41:25 PM
     Question to moderator.  Why does the (code)(/code) sequence mess up the display of a MASM listing so badly?


It is because you have a mixture of spaces and tabs in your source that you copied & pasted, and you are pasting it into a very simple edit window that doesn't always handle it nicely.

MazeGen

Michael,
your solution requires too much overhead from my point of view. Thanks anyway.

MazeGen

Ratch,
thanks for your elaboration. You have figured out how to simulate something like !ABOVE?, very interesting :8)

The condition !(!CARRY? && !ZERO?) is not much clear, I try to use some macro or something instead.

Quote from: Ratch on September 25, 2005, 11:20:08 PM
MazeGen,
     You're welcome.  Ratch

Sorry, I'm not native English speaker. What it means in this context here?

Ratch

MazeGen,
     It would be a wise and good thing to forget about using the flags to determine the relationship of two operands, except for simple relationships  That just obfuscates and often lengthens your code.  For instance, if you want to determine A > B, then you need to determine if ZF = 1 and SF != OF .  Since there is no single instruction that compares SF and OF except JL and JGE, why not make it easier on yourself and anyone else who reads your code by just using the relational jump in the first place.

Quote
The condition !(!CARRY? && !ZERO?) is not much clear, I try to use some macro or something instead.

     See what I mean?

Quote
Sorry, I'm not native English speaker. What it means in this context here?

     Forget it, it's not important.  Ratch

Farabi

Hai. Jz and je is all the same. So do jg or ja, so it cannot be happen.
(Am I wrong remember the opcode?)
Those who had universe knowledges can control the world by a micro processor.
http://www.wix.com/farabio/firstpage

"Etos siperi elegi"