5935735 [rkeene@sledge /home/rkeene/tmp]$ cat -n sse3.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    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 }
5935736 [rkeene@sledge /home/rkeene/tmp]$

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2006-02-09 16:54:11