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 0xf312 16 #define OP_SSE3_MOVSHDUP 0xf316 17 #define OP_SSE3_MOVDDUP 0xf212 18 #define OP_SSE3_ADDSUBPD 0x66d0 19 #define OP_SSE3_ADDSUBPS 0xf2d0 20 #define OP_SSE3_LDDQU 0xf2f0 21 #define OP_SSE3_HADDPD 0x667c 22 #define OP_SSE3_HSUBPD 0x667d 23 #define OP_SSE3_HADDPS 0xf27c 24 #define OP_SSE3_HSUBPS 0xf27d 25 26 #define OP_X86_NOP 0x90 27 28 static int have_sse3 = 1; 29 30 static void sse3_test_handler(int sig_nr, siginfo_t *info, void *p_context) { 31 ucontext_t *context = p_context; 32 33 have_sse3 = 0; 34 context->uc_mcontext.gregs[REG_EIP] += 4; 35 36 return; 37 } 38 39 static void sse3_handler(int sig_nr, siginfo_t *info, void *p_context) { 40 static int pagesize = 0; 41 static int in_handler = 0; 42 ucontext_t *context = p_context; 43 unsigned char *instruction; 44 unsigned char new_instructions[8] = {OP_X86_NOP, OP_X86_NOP, OP_X86_NOP, OP_X86_NOP, OP_X86_NOP, OP_X86_NOP, OP_X86_NOP, OP_X86_NOP}; 45 uint16_t opcode; 46 int instruction_len, new_instructions_len = 0; 47 int mprot_ret; 48 49 if (in_handler) { 50 return; 51 } 52 53 in_handler = 1; 54 55 if (!context) { 56 abort(); 57 } 58 59 if (pagesize == 0) { 60 pagesize = getpagesize(); 61 } 62 63 instruction = (char *) context->uc_mcontext.gregs[REG_EIP]; 64 opcode = (instruction[0] << 8) | instruction[2]; 65 66 mprot_ret = mprotect((void *) (((intptr_t) instruction) & ~(pagesize - 1)), pagesize, PROT_WRITE | PROT_READ | PROT_EXEC); 67 if (mprot_ret < 0) { 68 perror("mprotect"); 69 } 70 71 printf("EIP = %p\n", instruction); 72 printf("Instr = %04x,%02x,%02x\n", opcode, instruction[1], instruction[3]); 73 74 switch (opcode) { 75 case OP_SSE3_MOVSLDUP: 76 instruction_len = 4; 77 break; 78 case OP_SSE3_MOVSHDUP: 79 instruction_len = 4; 80 break; 81 case OP_SSE3_MOVDDUP: 82 instruction_len = 4; 83 break; 84 case OP_SSE3_ADDSUBPD: 85 instruction_len = 4; 86 break; 87 case OP_SSE3_ADDSUBPS: 88 instruction_len = 4; 89 break; 90 case OP_SSE3_LDDQU: 91 instruction_len = 8; 92 break; 93 case OP_SSE3_HADDPD: 94 instruction_len = 4; 95 break; 96 case OP_SSE3_HSUBPD: 97 instruction_len = 4; 98 break; 99 case OP_SSE3_HADDPS: 100 instruction_len = 4; 101 break; 102 case OP_SSE3_HSUBPS: 103 instruction_len = 4; 104 break; 105 default: 106 abort(); 107 } 108 109 /* 110 * Rewrite this so we can handle it faster next time. 111 */ 112 if (new_instructions_len) { 113 memcpy(instruction, new_instructions, new_instructions_len); 114 } 115 116 mprot_ret = mprotect((void *) (((intptr_t) instruction) & ~(pagesize - 1)), pagesize, PROT_READ | PROT_EXEC); 117 if (mprot_ret < 0) { 118 perror("mprotect"); 119 } 120 121 context->uc_mcontext.gregs[REG_EIP] += instruction_len; 122 123 in_handler = 0; 124 125 return; 126 } 127 128 void install_test_handler(void) { 129 struct sigaction act; 130 sigset_t masked; 131 132 act.sa_sigaction = sse3_test_handler; 133 act.sa_mask = masked; 134 act.sa_flags = SA_SIGINFO; 135 136 sigaction(SIGILL, &act, NULL); 137 138 return; 139 } 140 141 void uninstall_test_handler(void) { 142 struct sigaction act; 143 144 act.sa_handler = SIG_DFL; 145 act.sa_flags = 0; 146 147 sigaction(SIGILL, &act, NULL); 148 149 return; 150 } 151 152 void install_handler(void) { 153 struct sigaction act; 154 sigset_t masked; 155 156 act.sa_sigaction = sse3_handler; 157 act.sa_mask = masked; 158 act.sa_flags = SA_SIGINFO; 159 160 sigaction(SIGILL, &act, NULL); 161 162 return; 163 } 164 165 166 int main(void) { 167 int i; 168 169 printf("Trying to call some SSE3 instructions now...\n"); 170 171 install_test_handler(); 172 __asm__ ( "MOVSLDUP %xmm2,%xmm2 " ); 173 uninstall_test_handler(); 174 175 if (!have_sse3) { 176 printf("You do not have SSE3, installing handler.\n"); 177 install_handler(); 178 } else { 179 printf("You have SSE3, nothing will be done.\n"); 180 } 181 182 printf("Starting test:\n"); 183 for (i = 0; i < 10000000; i++) { 184 __asm__ ( "MOVSLDUP %xmm2,%xmm2 " ); 185 __asm__ ( "MOVSLDUP %xmm1,%xmm2 " ); 186 __asm__ ( "MOVSLDUP %xmm2,%xmm1 " ); 187 } 188 printf("done.\n"); 189 190 return(0); 191 } |