#include #include #include "8i.h" static char *opstr[] = { /* Edit s/O(.*),/[O\1]= "\1",/g */ [OBAD]= "BAD", [O0F]= "0F", [OAAA]= "AAA", [OAAD]= "AAD", [OAAM]= "AAM", [OAAS]= "AAS", [OADC]= "ADC", [OADD]= "ADD", [OAND]= "AND", [OARPL]= "ARPL", [OASIZE]= "ASIZE", [OBOUND]= "BOUND", [OBT]= "BT", [OBTS]= "BTS", [OCALL]= "CALL", [OCBW]= "CBW", [OCLC]= "CLC", [OCLD]= "CLD", [OCLI]= "CLI", [OCMC]= "CMC", [OCMOV]= "CMOV", [OCMP]= "CMP", [OCMPS]= "CMPS", [OCWD]= "CWD", [ODAA]= "DAA", [ODAS]= "DAS", [ODEC]= "DEC", [ODIV]= "DIV", [OENTER]= "ENTER", [OGP1]= "GP1", [OGP2]= "GP2", [OGP3b]= "GP3b", [OGP3v]= "GP3v", [OGP4]= "GP4", [OGP5]= "GP5", [OHLT]= "HLT", [OIDIV]= "IDIV", [OIMUL]= "IMUL", [OIN]= "IN", [OINC]= "INC", [OINS]= "INS", [OINT]= "INT", [OIRET]= "IRET", [OJUMP]= "JUMP", [OLAHF]= "LAHF", [OLFP]= "LFP", [OLEA]= "LEA", [OLEAVE]= "LEAVE", [OLOCK]= "LOCK", [OLODS]= "LODS", [OLOOP]= "LOOP", [OLOOPNZ]= "LOOPNZ", [OLOOPZ]= "LOOPZ", [OMOV]= "MOV", [OMOVS]= "MOVS", [OMUL]= "MUL", [ONEG]= "NEG", [ONOP]= "NOP", [ONOT]= "NOT", [OOR]= "OR", [OOSIZE]= "OSIZE", [OOUT]= "OUT", [OOUTS]= "OUTS", [OPOP]= "POP", [OPOPA]= "POPA", [OPOPF]= "POPF", [OPUSH]= "PUSH", [OPUSHA]= "PUSHA", [OPUSHF]= "PUSHF", [ORCL]= "RCL", [ORCR]= "RCR", [OREPE]= "REPE", [OREPNE]= "REPNE", [ORET]= "RET", [ORETF]= "RETF", [OROL]= "ROL", [OROR]= "ROR", [OSAHF]= "SAHF", [OSAR]= "SAR", [OSBB]= "SBB", [OSCAS]= "SCAS", [OSEG]= "SEG", [OSET]= "SET", [OSHL]= "SHL", [OSHLD]= "SHLD", [OSHR]= "SHR", [OSHRD]= "SHRD", [OSTC]= "STC", [OSTD]= "STD", [OSTI]= "STI", [OSTOS]= "STOS", [OSUB]= "SUB", [OTEST]= "TEST", [OWAIT]= "WAIT", [OXCHG]= "XCHG", [OXLAT]= "XLAT", [OXOR]= "XOR", NUMOP, }; static char *littlereg[] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" }; static char *bigreg[] = { "AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI", "ES", "CS", "SS", "DS", "FS", "GS", }; static int isstring(int a) { return a==AXb || a==AXv || a==AYb || a==AYv; } static char* memstr[] = { "BX+SI", "BX+DI", "BP+SI", "BP+DI", "SI", "DI", "BP", "BX", }; static void memconv(char *p, Inst *ip, Iarg*) { if(ip->sreg != 'D'){ sprint(p, "%cS:", ip->sreg); p += strlen(p); } if(ip->mod == 0 && ip->rm == 6){ sprint(p, "[%lX]", ip->disp); return; } if(ip->mod != 0) sprint(p, "[%s%+lX]", memstr[ip->rm], ip->disp); else sprint(p, "[%s]", memstr[ip->rm]); } static void argconv(char *p, Inst *ip, Iarg *iarg) { switch(iarg->atype){ default: case ANONE: /* no argument */ strcpy(p, ""); break; case A0: /* constant 0 */ strcpy(p, "0"); break; case A1: /* constant 1 */ strcpy(p, "1"); break; case A3: /* constant 3 */ strcpy(p, "3"); break; case A4: /* constant 4 */ strcpy(p, "4"); break; case AAp: /* 32-bit or 48-bit direct address */ case AMp: /* 32-bit or 48-bit memory address */ sprint(p, "[%4.4X:%*.*luX]", iarg->seg, ip->opsize/4, ip->opsize/4, iarg->off); break; case AEp: /* call indirect through memory */ print("call\n"); memconv(p, ip, iarg); break; case AEb: /* r/m8 from modrm byte */ if(ip->mod == 3){ sprint(p, littlereg[iarg->seg]); break; } memconv(p, ip, iarg); break; case AEv: /* r/m16 or r/m32 from modrm byte */ case AEw: /* r/m16 */ if(ip->mod == 3){ sprint(p, bigreg[iarg->seg]); break; } memconv(p, ip, iarg); break; case AFv: break; case AGb: /* r8 from modrm byte */ sprint(p, littlereg[iarg->seg]); break; case AGv: /* r16 or r32 from modrm byte */ case AGw: /* r/m16 */ sprint(p, bigreg[iarg->seg]); break; case AIb: /* immediate byte */ case AIc: /* immediate byte sign-extended */ case AIw: /* immediate 16-bit word */ case AIv: /* immediate 16-bit or 32-bit word */ sprint(p, "%*.*lX", ip->opsize/4, ip->opsize/4, iarg->val); break; case AJb: /* relative offset byte */ case AJv: /* relative offset 16-bit or 32-bit word */ sprint(p, "%*.*lX", ip->addrsize/4, ip->addrsize/4, iarg->off); break; case AJr: /* jump through register */ sprint(p, bigreg[ip->rm]); break; case AM: /* memory address from modrm */ case AMa: /* something for bound */ memconv(p, ip, iarg); break; case AMa2: break; case AOb: /* immediate word-sized offset to a byte */ case AOv: /* immediate word-size offset to a word */ memconv(p, ip, iarg); break; case ASw: /* segment register selected by r field of modrm */ sprint(p, bigreg[iarg->seg]); break; case AXb: /* byte at DS:SI (should not be called) */ case AXv: /* word at DS:SI */ case AYb: /* byte at ES:DI */ case AYv: /* word at ES:DI */ abort(); case AAL: /* registers; should be in same order as RAL: etc. */ case AAH: case ABL: case ABH: case ACL: case ACH: case ADL: case ADH: strcpy(p, littlereg[iarg->atype-AAL]); break; case AAX: /* registers; should be in same order as RAX: etc. */ case ABX: case ACX: case ADX: case ABP: case ASP: case ADI: case ASI: case AES: case ACS: case ASS: case ADS: case AFS: case AGS: strcpy(p, bigreg[iarg->atype - AAX]); break; } } static char *jmpstr[] = { "JO", "JNO", "JC", "JNC", "JZ", "JNZ", "JBE", "JA", "JS", "JNS", "JP", "JNP", "JL", "JGE", "JLE", "JG", }; int instfmt(Fmt *fmt) { int x; char buf[100]; Inst *ip; ip = va_arg(fmt->args, Inst*); if(ip == nil){ fmtstrcpy(fmt, ""); return 0; } if(ip->op == OBAD || ip->op >= NUMOP){ fmtstrcpy(fmt, "ILLEGAL INSTRUCTION"); return 0; } buf[0] = '\0'; if(ip->repeat) sprint(buf+strlen(buf), "%s: ", opstr[ip->repeat]); if(ip->opsize == 32) strcat(buf, "O32: "); if(ip->op == OJUMP){ switch(ip->i){ case 0xE3: strcat(buf, "JCXZ"); break; case 0xEB: case 0xE9: case 0xEA: case 0xFF: strcat(buf, "JMP"); break; default: strcat(buf, jmpstr[ip->i&0xF]); break; } }else strcat(buf, opstr[ip->op]); sprint(buf+strlen(buf), "(%c)", ip->opsize==8 ? 'B' : ip->opsize == 16 ? 'W' : 'L'); if(isstring(x=ip->arg1.atype) || isstring(x=ip->arg2.atype)){ // if(ip->opsize == 8) // strcat(buf, "B"); // else // strcat(buf, "W"); USED(x); }else{ if(ip->arg1.atype){ strcat(buf, "\t"); argconv(buf+strlen(buf), ip, &ip->arg1); } if(ip->arg2.atype){ strcat(buf, ", "); argconv(buf+strlen(buf), ip, &ip->arg2); } if(ip->arg3.atype){ strcat(buf, ", "); argconv(buf+strlen(buf), ip, &ip->arg3); } } fmtstrcpy(fmt, buf); return 0; }