Software Archive
Read-only legacy content
17061 Discussions

Get Status Word and Handle X87 FPU Exception

WLest
Beginner
685 Views
#include <stdio.h> 
#include <signal.h>  
void getStatus() {  
    short status;  
    __asm__(  
        "fnstsw %0\n\t":"=m"(status)  
    );  
    printf("0x%x\n", status);  
}  
void setUnmask() {  
    int cw = 0x366;  
    __asm__(  
        "fldcw %0\n\t"::"m"(cw)  
    );  
}  

/// Get the status register content of X87 FPU.   
short getExcepFlag() {  
    short status;  
    __asm__(  
         "fnstsw %0\n\t":"=m"(status):"m"(status)  
    );  
    return status;  
}  
int fpu(int value) {  
    int result = -1;  
    for (int i = 0; i < 10; ++i) {  
        __asm__(  
            "fldl %0\n\t":"=m"(result):"m"(value)  
        );  
        printf("normal\n");  
        getStatus();  
    }  
    return result;  
}  
void sigHandler(int sig) {  
    printf("Get an exception\n");  
    long temp;  
    short status = getExcepFlag();  
    printf("0x%x\n", status);  
    if (status & 0x00C0 == 0x00C0) {  
        if (status & 0x0200 == 0x0200) {  
            __asm__("fnclex\n\t");  
            __asm__("fstp %0\n\t":"+m"(temp):"m"(temp));  
        } else {  
  
        }  
        return;  
    }
}  
int main() {  
    setUnmask();  
    signal(SIGFPE, sigHandler);  
    fpu(123);  
}  

However, the result was not the same as what I expected.

First, if I did fldl 9 times(change i<10 to i<9), the status word showed there was an exception. (SW was 0x82c3) But my signal handler didn't get a signal and printed nothing.

Second, after fldl was executed 10 times, the sigHandler worked. But the returned value status was always 0x0, it seemed that the SW was cleared. Therefore my handler couldn't determine which was the exception.

Finally, the sigHandler would be executed infinite times. The printing wouldn't stop itself.

I have read D.3.4, Volume 1, Developer's Manual, and found some similar situations. But I am confused about that whether can I deal with the exception with C/C++ and signal(), because the examples are all written in assembly code.

My environment is Ubuntu 17.10.

 
 
0 Kudos
1 Reply
zalia64
New Contributor I
685 Views

It would have helped, if you  would have commented your code, and explained (to me and other readers) what you had in mind.

It is a bit complicated to debug a mixture of C and inline Assembly, when you know what is wanted.

It is twice as hard, when you must guess what the author had in mind.

Suggestion: write down the state of the internal FPU stack,   after each "push" of 

         __asm__ ( "fldl %0\n\t":"=m"(result):"m"(value)  ) ;

 
0 Kudos
Reply