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
pp_eflags(unsigned int _8bits_eflags)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 
main()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