5750897 [rkeene@sledge /home/rkeene/devel/old/sse3_emu-0.0.3]$ cat -n libsse3.c
  1 #include <sys/mman.h>
  2 #include <ucontext.h>
  3 #include <unistd.h>
  4 #include <stdlib.h>
  5 #include <signal.h>
  6 #include <stdint.h>
  7 #include <limits.h>
  8 #include <string.h>
  9 #include <stdio.h>
 10 
 11 #ifndef REG_EIP
 12 #define REG_EIP 14
 13 #endif
 14 
 15 #define OP_SSE3_MOVSLDUP    0x0ff312
 16 #define OP_SSE3_MOVSHDUP    0x0ff316
 17 #define OP_SSE3_MOVDDUP     0x0ff212
 18 #define OP_SSE3_ADDSUBPD    0x0f66d0
 19 #define OP_SSE3_ADDSUBPS    0x0ff2d0
 20 #define OP_SSE3_LDDQU       0x0ff2f0
 21 #define OP_SSE3_HADDPD      0x0f667c
 22 #define OP_SSE3_HSUBPD      0x0f667d
 23 #define OP_SSE3_HADDPS      0x0ff27c
 24 #define OP_SSE3_HSUBPS      0x0ff27d
 25 
 26 #define OP_NOP      0x90
 27 
 28 static int op_sse3_movsldup(ucontext_t *context, int instruction_len, unsigned char *data, unsigned char
	*new_instructions) {
 29     return(0);
 30 }
 31 
 32 static int have_sse3 = 1;
 33 
 34 static void sse3_handler(int sig_nr, siginfo_t *info, void *p_context) {
 35     static int pagesize = 0;
 36     static int in_handler = 0;
 37     ucontext_t *context = p_context;
 38     unsigned char *instruction;
 39     unsigned char new_instructions[8] = {OP_NOP, OP_NOP, OP_NOP, OP_NOP, OP_NOP, OP_NOP, OP_NOP, OP_NOP};
 40     uint32_t opcode;
 41     int instruction_len;
 42     int has_replacement = 0;
 43     int mprot_ret;
 44 
 45     if (in_handler) {
 46         return;
 47     }
 48 
 49     in_handler = 1;
 50 
 51     if (sig_nr != SIGILL) {
 52         return;
 53     }
 54 
 55     if (!info) {
 56         return;
 57     }
 58 
 59     if (!context) {
 60         abort();
 61     }
 62 
 63     if (pagesize == 0) {
 64         pagesize = getpagesize();
 65     }
 66 
 67     instruction = (char *) context->uc_mcontext.gregs[REG_EIP];
 68     opcode = (instruction[1] << 16) | (instruction[0] << 8) | instruction[2];
 69 
 70 //  printf("EIP = %p\n", instruction);
 71 //  printf("Instr = %06x,%02x,%02x\n", opcode, instruction[1], instruction[3]);
 72 
 73     switch (opcode) {
 74         case OP_SSE3_MOVSLDUP:
 75             instruction_len = 4;
 76 
 77             has_replacement = op_sse3_movsldup(context, instruction_len - 3, instruction + 3, new_instructions);
 78             break;
 79         case OP_SSE3_MOVSHDUP:
 80             instruction_len = 4;
 81             break;
 82         case OP_SSE3_MOVDDUP:
 83             instruction_len = 4;
 84             break;
 85         case OP_SSE3_ADDSUBPD:
 86             instruction_len = 4;
 87             break;
 88         case OP_SSE3_ADDSUBPS:
 89             instruction_len = 4;
 90             break;
 91         case OP_SSE3_LDDQU:
 92             instruction_len = 8;
 93             break;
 94         case OP_SSE3_HADDPD:
 95             instruction_len = 4;
 96             break;
 97         case OP_SSE3_HSUBPD:
 98             instruction_len = 4;
 99             break;
100         case OP_SSE3_HADDPS:
101             instruction_len = 4;
102             break;
103         case OP_SSE3_HSUBPS:
104             instruction_len = 4;
105             break;
106         default:
107             abort();
108     }
109 
110     /*
111      * Rewrite this so we can handle it faster next time.
112      */
113     if (has_replacement) {
114         mprot_ret = mprotect((void *) (((intptr_t) instruction) & ~(pagesize - 1)), pagesize, PROT_WRITE | PROT_READ |
	PROT_EXEC);
115         if (mprot_ret < 0) {
116             perror("mprotect");
117         }
118 
119         memcpy(instruction, new_instructions, instruction_len);
120 
121         mprot_ret = mprotect((void *) (((intptr_t) instruction) & ~(pagesize - 1)), pagesize, PROT_READ | PROT_EXEC);
122         if (mprot_ret < 0) {
123             perror("mprotect");
124         }
125     }
126 
127     context->uc_mcontext.gregs[REG_EIP] += instruction_len;
128 
129     in_handler = 0;
130 
131     return;
132 }
133 
134 #ifndef NO_SSE3_TEST
135 static void sse3_test_handler(int sig_nr, siginfo_t *info, void *p_context) {
136     ucontext_t *context = p_context;
137 
138     if (sig_nr != SIGILL) {
139         return;
140     }
141 
142     if (!info) {
143         return;
144     }
145 
146     have_sse3 = 0;
147     context->uc_mcontext.gregs[REG_EIP] += 4;
148 
149     return;
150 }
151 
152 static void install_test_handler(void) {
153     struct sigaction act;
154     sigset_t masked;
155 
156     act.sa_sigaction = sse3_test_handler;
157     act.sa_mask = masked;
158     act.sa_flags = SA_SIGINFO;
159 
160     sigaction(SIGILL, &act, NULL);
161 
162     return;
163 }
164 
165 static void uninstall_test_handler(void) {
166     struct sigaction act;
167 
168     act.sa_handler = SIG_DFL;
169     act.sa_flags = 0;
170 
171     sigaction(SIGILL, &act, NULL);
172 
173     return;
174 }
175 #endif
176 
177 static void install_handler(void) {
178     struct sigaction act;
179     sigset_t masked;
180 
181     act.sa_sigaction = sse3_handler;
182     act.sa_mask = masked;
183     act.sa_flags = SA_SIGINFO;
184 
185     sigaction(SIGILL, &act, NULL);
186 
187     return;
188 }
189 
190 
191 static int __attribute__((constructor)) load_sse3_handler(void) {
192 #ifdef DEBUG
193     printf("Trying to call some SSE3 instructions now...\n");
194 #endif
195 
196     install_test_handler();
197     __asm__ ( "MOVSLDUP %xmm2,%xmm2 " );
198     uninstall_test_handler();
199 
200     if (!have_sse3) {
201 #ifdef DEBUG
202         printf("You do not have SSE3, installing handler.\n");
203 #endif
204         install_handler();
205     } else {
206 #ifdef DEBUG
207         printf("You have SSE3, nothing will be done.\n");
208 #endif
209     }
210 
211     return(0);
212 }
5750898 [rkeene@sledge /home/rkeene/devel/old/sse3_emu-0.0.3]$

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2006-02-09 19:45:22