mirror of
https://github.com/ioacademy-jikim/debugging
synced 2025-06-08 08:26:14 +00:00
215 lines
6.8 KiB
C
215 lines
6.8 KiB
C
#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;
|
|
}
|