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 } |