1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdio.h> 2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <assert.h> 3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <string.h> 4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Test case supplied by Sergei Trofimovich */ 6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* 8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Real life example (MSDOS file INFO.EXE) has code like this 9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * 10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * I don't know why author/compiler done code like this. Only guess: 11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * guess 1 (strong :]): 12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * This archaic code was used by dynamic memory regeneration 13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * handler (according to code around it's called from 14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * interrupt handler). 15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * 16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * guess 2: cache flush (whether processors had caches at that time?) 17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * 18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * a disasmed snippet: 19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * 20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * mov byte ptr [bx], 0FFh 21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * sti 22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * mov cx, 0FFFFh ; 65535 23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * rep lods byte ptr es:[si] 24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * jcxz short somewhere_1 ; it seems code could be 25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * ; interrupted here 26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * 27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * call something_2 28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * cmp dx, 4 29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * mov byte ptr [bx], 0 30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * jmp somewhere_3 31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */ 32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define GET_BIT(var, bit_no) ((var >> bit_no) & 1) 34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic char sz_eflags[] = " "; // 8 spaces 36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void pp_eflags (unsigned int _8bits_eflags) 37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown assert (_8bits_eflags >= 0); 39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown assert (_8bits_eflags <= 0xFF); 40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sz_eflags[0] = GET_BIT(_8bits_eflags, 7) ? 'S' : ' '; 41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sz_eflags[1] = GET_BIT(_8bits_eflags, 6) ? 'Z' : ' '; 42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sz_eflags[3] = GET_BIT(_8bits_eflags, 4) ? 'A' : ' '; 43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sz_eflags[5] = GET_BIT(_8bits_eflags, 2) ? 'P' : ' '; 44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown sz_eflags[7] = GET_BIT(_8bits_eflags, 0) ? 'C' : ' '; 45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define EMIT_CALL(dir_insn, insn, in_eax, in_esi, in_eflags, out_eax, out_esi, out_eflags, count) \ 48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown asm volatile( \ 49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "movl %3, %%eax \t\n" \ 50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "sahf \t\n" /* loading our eflags */ \ 51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "movl %4, %%eax \t\n" \ 52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "movl %5, %%esi \t\n" \ 53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "movl %6, %%ecx \t\n" \ 54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown \ 55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown dir_insn "\t\n" \ 56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown insn "\t\n" \ 57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown \ 58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* return result */ \ 59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "movl %%eax, %0 \t\n" \ 60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "lahf \t\n" \ 61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "movl %%eax, %1 \t\n" \ 62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "movl %%esi, %2 \t\n" \ 63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "cld \t\n" \ 64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : "=d"(out_eax), \ 65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "=b"(out_eflags), \ 66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "=r"(out_esi) \ 67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown \ 68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : "m"(in_eflags), \ 69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "m"(in_eax), \ 70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "m"(in_esi), \ 71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "q"(count) \ 72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown \ 73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : "%eax", "%esi", "%ecx", "cc" /* we mess up EFLAGS */); 74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownconst signed char b_mem_buff[] = {-4, -3, -2, -1, 0xaa, 1, 2, 3, 4}; 76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownconst signed long l_mem_buff[] = {-4, -3, -2, -1, 0xaa, 1, 2, 3, 4}; 77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownconst signed short w_mem_buff[] = {-4, -3, -2, -1, 0xaa, 1, 2, 3, 4}; 78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownconst int lens[] = { 4, 3, 2, 1, 0, 0, 1, 2, 3, 4}; 80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownint main () 82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const signed char * b_center = (signed char *) memchr(b_mem_buff, 0xaa, sizeof (b_mem_buff)); 84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const signed char * w_center = (signed char *) memchr(w_mem_buff, 0xaa, sizeof (w_mem_buff)); 85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const signed char * l_center = (signed char *) memchr(l_mem_buff, 0xaa, sizeof (l_mem_buff)); 86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int insn; 88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (insn = 0; insn < 4; ++insn) //b,w[rep/addr],d,w[addr/rep] 89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int idx; 91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for (idx = 0; idx < sizeof (lens)/sizeof(lens[0]); ++idx) 92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown unsigned int eflags; 94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown unsigned int eax = 0x12348765; 95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown unsigned int esi; 96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const char * i_name = NULL; 97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown unsigned int resulting_eflags; 98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown unsigned int resulting_eax; 99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown unsigned int resulting_esi; 100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int len; 101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown int df; 102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown switch (insn) 104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case 0: //b 106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown esi = (unsigned int) b_center; 107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i_name = "lodsb"; 108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case 1: //w 110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown esi = (unsigned int) w_center; 111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i_name = "lodsw[rep/addr]"; 112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case 2: //d 114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown esi = (unsigned int) l_center; 115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i_name = "lodsl"; 116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case 3: //w 118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown esi = (unsigned int) w_center; 119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown i_name = "lodsw[addr/rep]"; 120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown eflags = 0; 124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pp_eflags ((eflags >> 8) & 0xFF); // scratching off AH 125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown printf ("REP %s (EAX = %08X, EFLAGS = %s) => ", i_name, eax, sz_eflags); 126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown resulting_eflags = 0; 128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown resulting_eax = 0; 129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown len = lens[idx]; 131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown df = (idx >= (sizeof(lens)/sizeof(lens[0]))/2); 132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown switch (insn) 134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case 0: //b 136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (df) 137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown EMIT_CALL("cld", 139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "rep lodsb", 140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags, 141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown len); 142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown else 144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown EMIT_CALL("std", 146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "rep lodsb", 147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags, 148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown len); 149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case 1: //w[rep/addr] 152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (df) 153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown EMIT_CALL("cld", 155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // "rep lodsw", 156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // explicit: rep-pref addr-pref op 157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ".byte 0x66,0xf3,0xad", 158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags, 159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown len); 160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown else 162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown EMIT_CALL("std", 164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // "rep lodsw", 165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // explicit: rep-pref addr-pref op 166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ".byte 0x66,0xf3,0xad", 167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags, 168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown len); 169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case 2: //d 172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (df) 173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown EMIT_CALL("cld", 175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "rep lodsl", 176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags, 177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown len); 178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown else 180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown EMIT_CALL("std", 182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "rep lodsl", 183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags, 184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown len); 185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown case 3: //w[addr/rep] 188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (df) 189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown EMIT_CALL("cld", 191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // "rep lodsw", 192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // explicit: rep-pref addr-pref op 193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ".byte 0xf3,0x66,0xad", 194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags, 195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown len); 196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown else 198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown EMIT_CALL("std", 200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // "rep lodsw", 201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // explicit: rep-pref addr-pref op 202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ".byte 0xf3,0x66,0xad", 203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown eax, esi, eflags, resulting_eax, resulting_esi, resulting_eflags, 204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown len); 205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown break; 207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown printf ("DF = %d, count = %2d ", df, len); 209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown pp_eflags ((resulting_eflags >> 8) & 0xFF); // scratching off AH 210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown printf ("(EAX = %08X, EFLAGS = %s)\n", resulting_eax, sz_eflags); 211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 0; 214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 215