1 #include <stdio.h> 2 #include <assert.h> 3 #include <string.h> 4 5 /* Test case supplied by Sergei Trofimovich */ 6 7 /* 8 * Real life example (MSDOS file INFO.EXE) has code like this 9 * 10 * I don't know why author/compiler done code like this. Only guess: 11 * guess 1 (strong :]): 12 * This archaic code was used by dynamic memory regeneration 13 * handler (according to code around it's called from 14 * interrupt handler). 15 * 16 * guess 2: cache flush (whether processors had caches at that time?) 17 * 18 * a disasmed snippet: 19 * 20 * mov byte ptr [bx], 0FFh 21 * sti 22 * mov cx, 0FFFFh ; 65535 23 * rep lods byte ptr es:[si] 24 * jcxz short somewhere_1 ; it seems code could be 25 * ; interrupted here 26 * 27 * call something_2 28 * cmp dx, 4 29 * mov byte ptr [bx], 0 30 * jmp somewhere_3 31 */ 32 33 #define GET_BIT(var, bit_no) ((var >> bit_no) & 1) 34 35 static char sz_eflags[] = " "; // 8 spaces 36 static void pp_eflags (unsigned int _8bits_eflags) 37 { 38 assert (_8bits_eflags >= 0); 39 assert (_8bits_eflags <= 0xFF); 40 sz_eflags[0] = GET_BIT(_8bits_eflags, 7) ? 'S' : ' '; 41 sz_eflags[1] = GET_BIT(_8bits_eflags, 6) ? 'Z' : ' '; 42 sz_eflags[3] = GET_BIT(_8bits_eflags, 4) ? 'A' : ' '; 43 sz_eflags[5] = GET_BIT(_8bits_eflags, 2) ? 'P' : ' '; 44 sz_eflags[7] = GET_BIT(_8bits_eflags, 0) ? 'C' : ' '; 45 } 46 47 #define EMIT_CALL(dir_insn, insn, in_eax, in_esi, in_eflags, out_eax, out_esi, out_eflags, count) \ 48 asm volatile( \ 49 "movl %3, %%eax \t\n" \ 50 "sahf \t\n" /* loading our eflags */ \ 51 "movl %4, %%eax \t\n" \ 52 "movl %5, %%esi \t\n" \ 53 "movl %6, %%ecx \t\n" \ 54 \ 55 dir_insn "\t\n" \ 56 insn "\t\n" \ 57 \ 58 /* return result */ \ 59 "movl %%eax, %0 \t\n" \ 60 "lahf \t\n" \ 61 "movl %%eax, %1 \t\n" \ 62 "movl %%esi, %2 \t\n" \ 63 "cld \t\n" \ 64 : "=d"(out_eax), \ 65 "=b"(out_eflags), \ 66 "=r"(out_esi) \ 67 \ 68 : "m"(in_eflags), \ 69 "m"(in_eax), \ 70 "m"(in_esi), \ 71 "q"(count) \ 72 \ 73 : "%eax", "%esi", "%ecx", "cc" /* we mess up EFLAGS */); 74 75 const signed char b_mem_buff[] = {-4, -3, -2, -1, 0xaa, 1, 2, 3, 4}; 76 const signed long l_mem_buff[] = {-4, -3, -2, -1, 0xaa, 1, 2, 3, 4}; 77 const signed short w_mem_buff[] = {-4, -3, -2, -1, 0xaa, 1, 2, 3, 4}; 78 79 const int lens[] = { 4, 3, 2, 1, 0, 0, 1, 2, 3, 4}; 80 81 int main () 82 { 83 const signed char * b_center = (signed char *) memchr(b_mem_buff, 0xaa, sizeof (b_mem_buff)); 84 const signed char * w_center = (signed char *) memchr(w_mem_buff, 0xaa, sizeof (w_mem_buff)); 85 const signed char * l_center = (signed char *) memchr(l_mem_buff, 0xaa, sizeof (l_mem_buff)); 86 87 int insn; 88 for (insn = 0; insn < 4; ++insn) //b,w[rep/addr],d,w[addr/rep] 89 { 90 int idx; 91 for (idx = 0; idx < sizeof (lens)/sizeof(lens[0]); ++idx) 92 { 93 unsigned int eflags; 94 unsigned int eax = 0x12348765; 95 unsigned int esi; 96 const char * i_name = NULL; 97 unsigned int resulting_eflags; 98 unsigned int resulting_eax; 99 unsigned int resulting_esi; 100 int len; 101 int df; 102 103 switch (insn) 104 { 105 case 0: //b 106 esi = (unsigned int) b_center; 107 i_name = "lodsb"; 108 break; 109 case 1: //w 110 esi = (unsigned int) w_center; 111 i_name = "lodsw[rep/addr]"; 112 break; 113 case 2: //d 114 esi = (unsigned int) l_center; 115 i_name = "lodsl"; 116 break; 117 case 3: //w 118 esi = (unsigned int) w_center; 119 i_name = "lodsw[addr/rep]"; 120 break; 121 } 122 123 eflags = 0; 124 pp_eflags ((eflags >> 8) & 0xFF); // scratching off AH 125 printf ("REP %s (EAX = %08X, EFLAGS = %s) => ", i_name, eax, sz_eflags); 126 127 resulting_eflags = 0; 128 resulting_eax = 0; 129 130 len = lens[idx]; 131 df = (idx >= (sizeof(lens)/sizeof(lens[0]))/2); 132 133 switch (insn) 134 { 135 case 0: //b 136 if (df) 137 { 138 EMIT_CALL("cld", 139 "rep lodsb", 140 eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags, 141 len); 142 } 143 else 144 { 145 EMIT_CALL("std", 146 "rep lodsb", 147 eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags, 148 len); 149 } 150 break; 151 case 1: //w[rep/addr] 152 if (df) 153 { 154 EMIT_CALL("cld", 155 // "rep lodsw", 156 // explicit: rep-pref addr-pref op 157 ".byte 0x66,0xf3,0xad", 158 eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags, 159 len); 160 } 161 else 162 { 163 EMIT_CALL("std", 164 // "rep lodsw", 165 // explicit: rep-pref addr-pref op 166 ".byte 0x66,0xf3,0xad", 167 eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags, 168 len); 169 } 170 break; 171 case 2: //d 172 if (df) 173 { 174 EMIT_CALL("cld", 175 "rep lodsl", 176 eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags, 177 len); 178 } 179 else 180 { 181 EMIT_CALL("std", 182 "rep lodsl", 183 eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags, 184 len); 185 } 186 break; 187 case 3: //w[addr/rep] 188 if (df) 189 { 190 EMIT_CALL("cld", 191 // "rep lodsw", 192 // explicit: rep-pref addr-pref op 193 ".byte 0xf3,0x66,0xad", 194 eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags, 195 len); 196 } 197 else 198 { 199 EMIT_CALL("std", 200 // "rep lodsw", 201 // explicit: rep-pref addr-pref op 202 ".byte 0xf3,0x66,0xad", 203 eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags, 204 len); 205 } 206 break; 207 } 208 printf ("DF = %d, count = %2d ", df, len); 209 pp_eflags ((resulting_eflags >> 8) & 0xFF); // scratching off AH 210 printf ("(EAX = %08X, EFLAGS = %s)\n", resulting_eax, sz_eflags); 211 } 212 } 213 return 0; 214 } 215