Fixing FPU control word on Unix

FPU handling on x86 machines is traditional area where black magic is used heavily. As an example, I'll share experience of fixing FPU control word from the signal handler. Some applications have tendency to silently corrupt FPU CW, and and in those configurations it could be helpful to fix those problems.

In my example, I'll intentionally corrupt bits in FPU CW, signal handler will fix them and execution happily continues.

#define _GNU_SOURCE 1

#include <fpu_control.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <ucontext.h>
#include <sys/ucontext.h>
#include <sys/mman.h>
#include <string.h>
#include <stdint.h>

short cw_orig;

void test();

void handle_signal(int sig, siginfo_t\* info, void\* ucVoid) {
  ucontext_t\* uc = (ucontext_t\*) ucVoid;
  intptr_t pc = (intptr_t)info->si_addr;
  short old_cw = uc->uc_mcontext.fpregs->cw;

  if ((uintptr_t)(pc-(intptr_t)&test) < 200 && old_cw != cw_orig) {
    printf("restore and go on...\\n");
    uc->uc_mcontext.fpregs->cw = cw_orig;    
    printf("CW: %x->%x\\n", old_cw, cw_orig);
  }  
}

void setup_sig() {
  struct sigaction act;
  memset(&act, 0, sizeof act);
  act.sa_handler = NULL;
  act.sa_sigaction = handle_signal;
  act.sa_flags  = SA_SIGINFO;
  sigaction(SIGFPE, &act, NULL);
}

void test() {
  int i;
  volatile double d = 0.01, v = 1.0;  
  for (i=0; i<100; i++) {
    v \*= d;  
    __asm__ __volatile__ 
      (
       "fldl %0\\n\\t"
       "fstl %0\\n\\t"
       : 
       : "m" (\*&d)
    );
  }

}

int main() {
  int i, bit;
  short cw;  
  
  setup_sig();
  
  
  _FPU_GETCW(cw);
  cw_orig = cw;
  printf("1: cw=%x\\n", cw);  
  test();


  for (bit = 0; bit < 16; bit++) {
    int mask = (1<<bit);
    if (mask & _FPU_RESERVED) {
      continue;
    }
    
    cw = cw_orig & ~mask;
    _FPU_SETCW(cw);
    printf("2: cw=%x\\n", cw);
    test();
  }
  
  return 0;
}
Comments:

Post a Comment:
  • HTML Syntax: NOT allowed
About

nike

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today