Home | History | Annotate | Download | only in x86
      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