Assembly: JA and JB work incorrectly

688 views Asked by At

Since my main OS is linux and have project on visual studio, I decided to use online compilers to achieve it. I found this which was suggested by many. So here is my code:

#include <iostream>

using namespace std;
int main(void) {
float a = 1;
float b = 20.2;
float res = 0;
float res1 = 0;

_asm { 

    FLD a
    FCOM b
    JA midi
    JMP modi           

    midi:
    FST res
    JMP OUT

    modi:
    FST res1
    JMP OUT


}
    OUT:
cout << "res = " << res << endl;
cout << "res1 = " << res1 << endl;
return 0;
}

My goal is simple, if a is greater that b than put a in res, otherwise in res1. But it seems like whatever I have in variable a it always jumps on midi and result is always res = whatever is in a. Hope you can help. Sorry if my questions is silly, I've just started to learn assembly. thanks :)

P.S
same thing goes with JB but the opposite. It always prints res1 = whatever is in b.

2

There are 2 answers

5
Weather Vane On BEST ANSWER

From this page:

FCOM compares ST0 with the given operand, and sets the FPU flags accordingly.

But your JA midi is testing the CPU flags.

It goes on:

FCOMI and FCOMIP work like the corresponding forms of FCOM and FCOMP, but write their results directly to the CPU flags register rather than the FPU status word, so they can be immediately followed by conditional jump or conditional move instructions.

0
Margaret Bloom On

This is a common pitfall, FCOM doesn't set the flags in the flags register, it sets the condition code flags in the FPU status word.
From Intel manual 2:

Compares the contents of register ST(0) and source value and sets condition code flags C0, C2, and C3 in the FPU status word according to the results (see the table below)

Condition codes set by FCOM

Where you can see that C3 takes the role of ZF and C1 of CF.

Use FCOMI/FUCOMI (and variants) to set the flags accordingly.

Performs an unordered comparison of the contents of registers ST(0) and ST(i) and sets the status flags ZF, PF, and CF in the EFLAGS register according to the results [Table is identical to the above, where C2 is PF].

The difference between FCOMI and FUCOMI is that the latter allow for unordered operands, i.e. qNaNs.


Alternatively you can still use FCOM but then move the condition codes to the flags with:

fnstsw ax        ;FP Not-checked STore Status Word in AX
sahf             ;Store AH into flags

Intel designed fnstsw to be compatible with sahf.
The former moves C3, C2 and C1 to bit6, bit2 and bit0, respectively, of AH.
The latter set the flags as RFLAGS(SF:ZF:0:AF:0:PF:1:CF) ← AH.


You can also test ax directly after the fnstsw ax as suggested in Section 8.3.6.1 Branching on the x87 FPU Condition Codes of manual 1.

Constants to test AX against after fnstsw for various conditions