The MASM Forum

General => The Campus => Topic started by: Joao Batista on November 27, 2012, 03:17:26 AM

Title: Overflow problem
Post by: Joao Batista on November 27, 2012, 03:17:26 AM
Hello, i'm having issues checking overflow while adding.
We are making a really basic compiler, my code is:


Array b[2.];
b[1.]:=1.;
b[1.]:=b[1.]+1.2;


And this is what we are generating on masm32

.386
.model flat, stdcall
option casemap :none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
include    \masm32\include\masm32.inc
includelib \masm32\lib\masm32.lib
include    \masm32\include\debug.inc
includelib \masm32\lib\debug.lib
.data
nombre db "Compilador",0
EDIV0 db "Error: Division por 0",0
EOVER db "Error: Overflow en la suma",0
cte0 dq 0
cte6 dq 1.2
cte5 dq 1.
cte4 dq 1.
cte3 dq 1.
cte2 dq 1.
cte1 dq 2.
_@7 dq 0
_@6 dq 0000h
_@5 dq 0
_@1 dq 0
_b dq 2 dup (0000h)

.code
start:

FLD _b
FADD _@1
FSTP _@1
FLD cte3
FSTP qword ptr[_@1]
FWAIT
FLD cte3
FLD cte3
FCOMP
fstsw ax
sahf
JBE ET10
JMP ABORT
ET10:
FLD cte1
FLD cte3
FCOMP
fstsw ax
sahf
JBE ET16
JMP ABORT
ET16:
FLD _b
FADD _@5
FSTP _@5
FLD qword ptr [_@5]
FWAIT
FSTP _@5
FLD _@5
FLD cte6
FADD
FSTP _@6
JC OVER

FLD _b
FADD _@7
FSTP _@7
FLD _@6
FSTP qword ptr[_@7]
FWAIT
invoke ExitProcess,0
DIV0:
invoke MessageBox, NULL, addr EDIV0, addr nombre, MB_OK
JMP ABORT
OVER:
invoke MessageBox, NULL, addr EOVER, addr nombre, MB_OK
JMP ABORT
ABORT:
invoke ExitProcess,1
end start


My questions are:
1. Is correct to use
fstsw ax
sahf
while checking for flags on the coprocessor? or is there another way to do this?
2. Why does this code generate an add overflow while it shouldn't ?

Thanks in advance.
Title: Re: Overflow problem
Post by: dedndave on November 27, 2012, 04:27:30 AM
you should define those as REAL8, not QWORD

1.7976931348623158^308 is the max  :P

fstsw ax
sahf
is ok, i guess - but, you will get an exception when it overflows (next century), not a math flag
Title: Re: Overflow problem
Post by: jj2007 on November 27, 2012, 04:31:53 AM
FLD _@5
FLD cte6
FADD   ; <<<<<< FPU instruction does not set CPU flags
FSTP _@6
JC OVER
Title: Re: Overflow problem
Post by: qWord on November 27, 2012, 04:39:10 AM
Quote from: dedndave on November 27, 2012, 04:27:30 AM
you should define those as REAL8, not QWORD
that syntax is strange, but OK as long as using a dot in the declaration.
Quote from: Joao Batista on November 27, 2012, 03:17:26 AM
My questions are:
fstsw ax
sahf
is there another way to do this?
this method is obsolete - use FCOMI[P]/FUCOMI[P] instead.
Title: Re: Overflow problem
Post by: Joao Batista on November 27, 2012, 05:12:20 AM
mm ok.. so..

FLD _@5
FLD cte6
FADD
FSTP _@6
JC OVER


here the FADD doesn't set the cpu flags.. how do i do that then?

and.. how do i use FCOM? FCOMI.. etc?

i tried something like

FLD _@5
FLD cte6
FCOM
JC OVER
FADD
FSTP _@6


but this doesnt work..
yeah.. im kinda lost here hehe
Title: Re: Overflow problem
Post by: qWord on November 27, 2012, 05:21:02 AM
f[i]ld a
f[i]ld b
fcomip
fstp st
ja @A_GE_B
jb @A_LT_B
jz @A_EQ_B
jae ...
jp @error

AMD64 Architecture Programmer's Manual Volume 5: 64-Bit Media and x87 Floating-Point Instructions (http://support.amd.com/us/Processor_TechDocs/26569_APM_v5.pdf)
Title: Re: Overflow problem
Post by: dedndave on November 27, 2012, 05:24:30 AM
Ray's FPU tutorial is probably a little easier to understand...

http://www.ray.masmcode.com/fpu.html (http://www.ray.masmcode.com/fpu.html)
Title: Re: Overflow problem
Post by: Joao Batista on November 27, 2012, 05:28:20 AM
ok ill start reading, ty, but just one problem.
I keep geting "Instruction or register not accepted in current CPU mode" error
how do i set the cpu mode to work with that?
Title: Re: Overflow problem
Post by: Gunther on November 27, 2012, 05:57:14 AM
Hi Joao,

Quote from: Joao Batista on November 27, 2012, 05:28:20 AM
ok ill start reading, ty, but just one problem.
I keep geting "Instruction or register not accepted in current CPU mode" error
how do i set the cpu mode to work with that?

did you try .387 after .386?

Gunther
Title: Re: Overflow problem
Post by: jj2007 on November 27, 2012, 06:07:20 AM
The fcomip needs probably .586 or .686 - just try...
Title: Re: Overflow problem
Post by: dedndave on November 27, 2012, 06:07:44 AM
i think .686 is required   :t
Title: Re: Overflow problem
Post by: Joao Batista on November 27, 2012, 07:22:08 AM
Ok thank you all for the help.. i have to wait until tomorrow to try all this so.. see you tomorrow!
Thanks again!
Title: Re: Overflow problem
Post by: MichaelW on November 27, 2012, 04:21:03 PM
One possibility is to store the status word and test the exception status bits.

;==============================================================================
include \masm32\include\masm32rt.inc
;.686
;==============================================================================

;--------------------------------------------------
; Equates for the FPU status word exception flags.
;--------------------------------------------------

FEX_INVALID      equ 1
FEX_DENORMALIZED equ 2
FEX_ZERODIVIDE   equ 4
FEX_OVERFLOW     equ 8
FEX_UNDERFLOW    equ 16
FEX_PRECISION    equ 32
FEX_STACKFAULT   equ 64
FEX_ANY          equ 127

;==============================================================================
.data
    r10max      REAL10  1.18E4932  ; approximate
    r8          REAL8   0.0
    fpu_status  dd 0
.code
;==============================================================================
start:
;==============================================================================

    fstsw WORD PTR fpu_status
    test fpu_status, FEX_OVERFLOW
    jz @F
    printf("OF 0\n")
  @@:

    fld r10max
    fld r10max
    fadd

    fstsw WORD PTR fpu_status
    test fpu_status, FEX_OVERFLOW
    jz @F
    printf("OF 1\n")
  @@:

    fstp st
    fclex

    fld r10max
    fstp r8
    fstsw WORD PTR fpu_status
    test fpu_status, FEX_OVERFLOW
    jz @F
    printf("OF 2\n")
  @@:

    fclex

    fld1
    fstp r8
    fstsw WORD PTR fpu_status
    test fpu_status, FEX_OVERFLOW
    jz @F
    printf("OF 3\n")
  @@:

    fclex

    inkey
    exit

;==============================================================================
Title: Re: Overflow problem
Post by: dedndave on November 27, 2012, 10:09:39 PM
using real8's, and starting at 1.0...
adding 1.2 with each pass...
i don't think you will live long enough to see it overflow   :biggrin:

refer to reply #1 - lol
http://masm32.com/board/index.php?topic=959.msg8657#msg8657 (http://masm32.com/board/index.php?topic=959.msg8657#msg8657)
Title: Re: Overflow problem
Post by: Joao Batista on November 27, 2012, 11:32:10 PM
Hi, yeah the thing with the dq is that i must use them.. i know it sounds silly, but you will have to tell that to my professor -.-
So is a restriction i have to live with.
Title: Re: Overflow problem
Post by: dedndave on November 27, 2012, 11:37:50 PM
ok - but read the rest of that post   :P
Title: Re: Overflow problem
Post by: Joao Batista on November 28, 2012, 11:08:14 AM
Hi, i still can't make this work :S

can you just give me a super simple example.. using dq, of how to check for add overflow on the fpu and jump to another tag?

i tried everything u told me to :S

i must be doing somehing wrong :S

tried this
FLD cte1
FLD cte2

FADD
fstsw WORD PTR fpu_status
    test fpu_status, FEX_OVERFLOW
    jz OVER


tried this

FLD cte0
FLD cte6


FCOMI ST,ST(0)
fwait
Jc OVER


and so on.. :S
Title: Re: Overflow problem
Post by: dedndave on November 28, 2012, 11:25:49 AM
in your program, you may want to do an FINIT and set the precision
under windows, when a program is loaded, i think it is initialized and set to double precision (8 byte)
FINIT sets it to extended real (10 byte)
that is just something to note - may not be your problem
once you have that set up.....

    fld     cte1
    fld     cte2
    fadd
    fstsw   ax
    test    al,FEX_OVERFLOW
    jnz     OverFlow_Occured


use something like 1.78E308 for both cte1 and cte2 - that should cause an overflow
Title: Re: Overflow problem
Post by: Joao Batista on November 28, 2012, 11:30:49 AM
Quote from: dedndave on November 28, 2012, 11:25:49 AM
in your program, you may want to do an FINIT and set the precision
under windows, when a program is loaded, i think it is initialized and set to double precision (8 byte)
FINIT sets it to extended real (10 byte)
that is just something to note - may not be your problem
once you have that set up.....

    fld     cte1
    fld     cte2
    fadd
    fstsw   ax
    test    al,FEX_OVERFLOW
    jnz     OverFlow_Occured


use 1.78E308 for both cte1 and cte2 - that should cause an overflow

just tried this and doesnt work :S

And just when you just told me that, i was trying to do what ray's tutorial says..

cte0 dq 1.39769e+308
cte6 dq 1.79769e+308
.code
start:

FLD cte0
FLD cte6
FADD
fstsw ax
fwait
sahf
JC OVER


this seems perfect.. but doesn't work :S

fld loads cte0 and 6 in st
then i add them
fstsw ax is supposed to store the flags on ax register
fwait .. wait while fpu is busy
sahf is supposed to "pass" fpu flags to cpu..
JC OVER is supposed to jump if the carry flag is up

:( what's wrong??
Title: Re: Overflow problem
Post by: dedndave on November 28, 2012, 11:35:04 AM
hmmmmm
the FPU is using REAL10 format, internally - which it always does except for integer and bcd values
perhaps you won't get an overflow until you try to store it into a REAL8 - lol

another way to try it would be to go ahead and do an FINIT
that sets it to REAL10 precision
then test to see if you can cause an overflow using REAL10's
the max value is about 1.19E4932
so, you can add 1.0E4932 to itself to get an overflow
Title: Re: Overflow problem
Post by: dedndave on November 28, 2012, 11:39:13 AM
as you can see, most of us have never tried to overflow the FPU   :lol:
we generally have our hands full testing for equality or "near-equality"
Title: Re: Overflow problem
Post by: Joao Batista on November 28, 2012, 11:43:57 AM
Yeah is not that we are trying to make it overflow.. i have to test if our code works XD

like this!!

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

FEX_OVERFLOW equ 8

.data
nombre db "Compilador",0
DIV0 db "Termino",0
EOVER db "Error: Overflow en la suma",0
cte0 dq 1.78E308
cte6 dq 1.78E308
.code
start:
FINIT
FWAIT
FLD cte0
FLD cte6
FADD
fstsw ax
fwait
sahf
JC OVER
JMP EDIV0

invoke ExitProcess,0
EDIV0:
invoke MessageBox, NULL, addr DIV0, addr nombre, MB_OK
JMP ABORT
OVER:
invoke MessageBox, NULL, addr EOVER, addr nombre, MB_OK
JMP ABORT
ABORT:
invoke ExitProcess,1
end start


This doesn't work! and we don't know why!! :P

Thing is, my profesor will test our code with a 1.78E308 + 1.78E308 value and our program should show a message saying hey.. fpu overflowed .. :(
Title: Re: Overflow problem
Post by: qWord on November 28, 2012, 11:45:52 AM
As dave said, the OF exception occurs when you store the value. A simple approach would be to test the result for NaN after it has been stored in memory (requires that the input values are valid):
mov eax,DWORD ptr r8Var[4]
and eax,7FF00000h
xor eax,7FF00000h
jz @error


EDIT: code changed
Title: Re: Overflow problem
Post by: Joao Batista on November 28, 2012, 11:49:07 AM
O.o i didn't understand a single word of that code lol

where do i add it on my code? hahaha

Quote from: qWord on November 28, 2012, 11:45:52 AM
As dave said, the OF exception occurs when you store the value. A simple approach would be to test the result for NaN after it has been stored in memory (requires that the input values are valid):
and DWORD ptr r8Var[4],7FF00000h
xor DWORD ptr r8Var[4],7FF00000h
jz @error

Title: Re: Overflow problem
Post by: qWord on November 28, 2012, 11:54:26 AM
.386
.model flat, stdcall
option casemap :none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
include    \masm32\include\masm32.inc
includelib \masm32\lib\masm32.lib
include    \masm32\include\debug.inc
includelib \masm32\lib\debug.lib

FEX_OVERFLOW equ 8

.data
nombre db "Compilador",0
DIV0 db "Termino",0
EOVER db "Error: Overflow en la suma",0
cte0 dq 1.78E308
cte6 dq 0
result dq ?
.code
start:
FINIT
FWAIT
FLD cte0
FLD cte6
FADDp
fstp result
mov eax,DWORD ptr result[4]
and eax,7FF00000h
xor eax,7FF00000h
jz OVER
JMP EDIV0

invoke ExitProcess,0
EDIV0:
invoke MessageBox, NULL, addr DIV0, addr nombre, MB_OK
JMP ABORT
OVER:
invoke MessageBox, NULL, addr EOVER, addr nombre, MB_OK
JMP ABORT
ABORT:
invoke ExitProcess,1
end start

As said, this method makes only sense if the input values are validated (and not NaN themself)
Title: Re: Overflow problem
Post by: qWord on November 28, 2012, 11:58:34 AM
BTW, what you can also do is to unmask the wished exceptions and then enclose you calculation by corresponding exception handler (SEH).
Title: Re: Overflow problem
Post by: Joao Batista on November 28, 2012, 12:01:40 PM
Quote from: qWord on November 28, 2012, 11:54:26 AM
.386
.model flat, stdcall
option casemap :none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
include    \masm32\include\masm32.inc
includelib \masm32\lib\masm32.lib
include    \masm32\include\debug.inc
includelib \masm32\lib\debug.lib

FEX_OVERFLOW equ 8

.data
nombre db "Compilador",0
DIV0 db "Termino",0
EOVER db "Error: Overflow en la suma",0
cte0 dq 1.78E308
cte6 dq 0
result dq ?
.code
start:
FINIT
FWAIT
FLD cte0
FLD cte6
FADDp
fstp result
mov eax,DWORD ptr result[4]
and eax,7FF00000h
xor eax,7FF00000h
jz OVER
JMP EDIV0

invoke ExitProcess,0
EDIV0:
invoke MessageBox, NULL, addr DIV0, addr nombre, MB_OK
JMP ABORT
OVER:
invoke MessageBox, NULL, addr EOVER, addr nombre, MB_OK
JMP ABORT
ABORT:
invoke ExitProcess,1
end start

As said, this method makes only sense if the input values are validated (and not NaN themself)

so basically.. u have to store the value to make the overflow? O.o

btw.. that worked with a FADD instead of a FADDP .. :D

So. thank you very very much!!!
Title: Re: Overflow problem
Post by: jj2007 on November 28, 2012, 05:20:41 PM
Quote from: Joao Batista on November 28, 2012, 12:01:40 PM
btw.. that worked with a FADD instead of a FADDP .. :D

Yes it does but it leaves a value in the FPU. Do that 8 times, e.g. in a loop, and the FPU chokes. And you have a bug that can be chased only with Olly...
Title: Re: Overflow problem
Post by: FORTRANS on November 30, 2012, 04:05:59 AM
Quote from: jj2007 on November 28, 2012, 05:20:41 PM
Quote from: Joao Batista on November 28, 2012, 12:01:40 PM
btw.. that worked with a FADD instead of a FADDP .. :D

Yes it does but it leaves a value in the FPU. Do that 8 times, e.g. in a loop, and the FPU chokes. And you have a bug that can be chased only with Olly...

Hi,

   Yes, but using FADD with no operands is a special case.
It defaults to adding ST and ST(1) and then popping.  ST
is ST(0) as well.  It's a MASM (and other assemblers) thing.



0005  9B DC C1         FADD    ST(1),ST
0008  9B DE C1         FADDP   ST(1),ST
000B  9B DE C1         FADD



Regards,

Steve N.
Title: Re: Overflow problem
Post by: jj2007 on November 30, 2012, 08:52:16 AM
Quote from: FORTRANS on November 30, 2012, 04:05:59 AM
using FADD with no operands .. defaults to adding ST and ST(1) and then popping.

Interesting, thanks Steve :t