| #include <stdio.h> |
| #include <assert.h> |
| #include <string.h> |
| |
| /* Test case supplied by Sergei Trofimovich */ |
| |
| /* |
| * Real life example (MSDOS file INFO.EXE) has code like this |
| * |
| * I don't know why author/compiler done code like this. Only guess: |
| * guess 1 (strong :]): |
| * This archaic code was used by dynamic memory regeneration |
| * handler (according to code around it's called from |
| * interrupt handler). |
| * |
| * guess 2: cache flush (whether processors had caches at that time?) |
| * |
| * a disasmed snippet: |
| * |
| * mov byte ptr [bx], 0FFh |
| * sti |
| * mov cx, 0FFFFh ; 65535 |
| * rep lods byte ptr es:[si] |
| * jcxz short somewhere_1 ; it seems code could be |
| * ; interrupted here |
| * |
| * call something_2 |
| * cmp dx, 4 |
| * mov byte ptr [bx], 0 |
| * jmp somewhere_3 |
| */ |
| |
| #define GET_BIT(var, bit_no) ((var >> bit_no) & 1) |
| |
| static char sz_eflags[] = " "; // 8 spaces |
| static void pp_eflags (unsigned int _8bits_eflags) |
| { |
| assert (_8bits_eflags >= 0); |
| assert (_8bits_eflags <= 0xFF); |
| sz_eflags[0] = GET_BIT(_8bits_eflags, 7) ? 'S' : ' '; |
| sz_eflags[1] = GET_BIT(_8bits_eflags, 6) ? 'Z' : ' '; |
| sz_eflags[3] = GET_BIT(_8bits_eflags, 4) ? 'A' : ' '; |
| sz_eflags[5] = GET_BIT(_8bits_eflags, 2) ? 'P' : ' '; |
| sz_eflags[7] = GET_BIT(_8bits_eflags, 0) ? 'C' : ' '; |
| } |
| |
| #define EMIT_CALL(dir_insn, insn, in_eax, in_esi, in_eflags, out_eax, out_esi, out_eflags, count) \ |
| asm volatile( \ |
| "movl %3, %%eax \t\n" \ |
| "sahf \t\n" /* loading our eflags */ \ |
| "movl %4, %%eax \t\n" \ |
| "movl %5, %%esi \t\n" \ |
| "movl %6, %%ecx \t\n" \ |
| \ |
| dir_insn "\t\n" \ |
| insn "\t\n" \ |
| \ |
| /* return result */ \ |
| "movl %%eax, %0 \t\n" \ |
| "lahf \t\n" \ |
| "movl %%eax, %1 \t\n" \ |
| "movl %%esi, %2 \t\n" \ |
| "cld \t\n" \ |
| : "=d"(out_eax), \ |
| "=b"(out_eflags), \ |
| "=r"(out_esi) \ |
| \ |
| : "m"(in_eflags), \ |
| "m"(in_eax), \ |
| "m"(in_esi), \ |
| "q"(count) \ |
| \ |
| : "%eax", "%esi", "%ecx", "cc" /* we mess up EFLAGS */); |
| |
| const signed char b_mem_buff[] = {-4, -3, -2, -1, 0xaa, 1, 2, 3, 4}; |
| const signed long l_mem_buff[] = {-4, -3, -2, -1, 0xaa, 1, 2, 3, 4}; |
| const signed short w_mem_buff[] = {-4, -3, -2, -1, 0xaa, 1, 2, 3, 4}; |
| |
| const int lens[] = { 4, 3, 2, 1, 0, 0, 1, 2, 3, 4}; |
| |
| int main () |
| { |
| const signed char * b_center = (signed char *) memchr(b_mem_buff, 0xaa, sizeof (b_mem_buff)); |
| const signed char * w_center = (signed char *) memchr(w_mem_buff, 0xaa, sizeof (w_mem_buff)); |
| const signed char * l_center = (signed char *) memchr(l_mem_buff, 0xaa, sizeof (l_mem_buff)); |
| |
| int insn; |
| for (insn = 0; insn < 4; ++insn) //b,w[rep/addr],d,w[addr/rep] |
| { |
| int idx; |
| for (idx = 0; idx < sizeof (lens)/sizeof(lens[0]); ++idx) |
| { |
| unsigned int eflags; |
| unsigned int eax = 0x12348765; |
| unsigned int esi; |
| const char * i_name = NULL; |
| unsigned int resulting_eflags; |
| unsigned int resulting_eax; |
| unsigned int resulting_esi; |
| int len; |
| int df; |
| |
| switch (insn) |
| { |
| case 0: //b |
| esi = (unsigned int) b_center; |
| i_name = "lodsb"; |
| break; |
| case 1: //w |
| esi = (unsigned int) w_center; |
| i_name = "lodsw[rep/addr]"; |
| break; |
| case 2: //d |
| esi = (unsigned int) l_center; |
| i_name = "lodsl"; |
| break; |
| case 3: //w |
| esi = (unsigned int) w_center; |
| i_name = "lodsw[addr/rep]"; |
| break; |
| } |
| |
| eflags = 0; |
| pp_eflags ((eflags >> 8) & 0xFF); // scratching off AH |
| printf ("REP %s (EAX = %08X, EFLAGS = %s) => ", i_name, eax, sz_eflags); |
| |
| resulting_eflags = 0; |
| resulting_eax = 0; |
| |
| len = lens[idx]; |
| df = (idx >= (sizeof(lens)/sizeof(lens[0]))/2); |
| |
| switch (insn) |
| { |
| case 0: //b |
| if (df) |
| { |
| EMIT_CALL("cld", |
| "rep lodsb", |
| eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags, |
| len); |
| } |
| else |
| { |
| EMIT_CALL("std", |
| "rep lodsb", |
| eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags, |
| len); |
| } |
| break; |
| case 1: //w[rep/addr] |
| if (df) |
| { |
| EMIT_CALL("cld", |
| // "rep lodsw", |
| // explicit: rep-pref addr-pref op |
| ".byte 0x66,0xf3,0xad", |
| eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags, |
| len); |
| } |
| else |
| { |
| EMIT_CALL("std", |
| // "rep lodsw", |
| // explicit: rep-pref addr-pref op |
| ".byte 0x66,0xf3,0xad", |
| eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags, |
| len); |
| } |
| break; |
| case 2: //d |
| if (df) |
| { |
| EMIT_CALL("cld", |
| "rep lodsl", |
| eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags, |
| len); |
| } |
| else |
| { |
| EMIT_CALL("std", |
| "rep lodsl", |
| eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags, |
| len); |
| } |
| break; |
| case 3: //w[addr/rep] |
| if (df) |
| { |
| EMIT_CALL("cld", |
| // "rep lodsw", |
| // explicit: rep-pref addr-pref op |
| ".byte 0xf3,0x66,0xad", |
| eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags, |
| len); |
| } |
| else |
| { |
| EMIT_CALL("std", |
| // "rep lodsw", |
| // explicit: rep-pref addr-pref op |
| ".byte 0xf3,0x66,0xad", |
| eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags, |
| len); |
| } |
| break; |
| } |
| printf ("DF = %d, count = %2d ", df, len); |
| pp_eflags ((resulting_eflags >> 8) & 0xFF); // scratching off AH |
| printf ("(EAX = %08X, EFLAGS = %s)\n", resulting_eax, sz_eflags); |
| } |
| } |
| return 0; |
| } |