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