/********************************************************************/
/* Desensambladorx86IA16.c */
/* */
/* */
/* Copyright (c) 1997-2006 Rafael Rico (rafael.rico@uah.es) */
/* */
/* Este fichero forma parte de ADD */
/* (Analizador de Dependencias de Datos) */
/* Version 5.10. */
/* */
/* */
/* ADD es software libre. Puede redistribuirlo y/o modificarlo */
/* bajo los términos de la Licencia Pública General de GNU */
/* según es publicada por la Free Software Foundation, bien bajo */
/* la versión 2 de dicha Licencia o bien (según su elección) */
/* bajo cualquier versión posterior. */
/* */
/* ADD se distribuye con la esperanza de que sea útil, */
/* pero SIN NINGUNA GARANTÍA, incluso sin la garantía MERCANTIL */
/* implícita y sin garantizar la CONVENIENCIA PARA UN PROPÓSITO */
/* PARTICULAR. Véase la Licencia Pública General de GNU para */
/* más detalles. */
/* */
/* Debería haber recibido una copia de la Licencia Pública General */
/* junto con ADD. Si no ha sido así, escriba a la Free Software */
/* Foundation, Inc., 51 Franklin St, Fifth Floor, */
/* Boston, MA 02110-1301 EEUU. */
/* */
/* -------------------------- Historia --------------------------- */
/* */
/* $Id: Desensambladorx86IA16.c,v 1.2 2006/02/28 14:54:21 rico Exp $ */
/* */
/* Revisión 1.2. 01/2006 */
/* Se añade la licencia GPL y documentación en estilo Javadoc */
/* */
/* Revisión 1.1. 09/2005 */
/* Versión inicial */
/* */
/********************************************************************/
/******************************************************************************/
/* MÓDULO: DesensambladorX86IA16.c */
/* */
/* Este módulo determina el nemónico, los operandos y la longitud del */
/* formato a partir de una cadena de bytes del código binario del ejecutable. */
/* - El nemónico depende del código de operación y en casos excepcionales */
/* del 2º byte. */
/* - Los operandos dependen del modo de direccionamiento (a través del código */
/* de operación) y de los bytes del formato. */
/******************************************************************************/
/* Fecha: 29 de junio de 2005 */
/******************************************************************************/
#include <stdio.h>
#include <string.h>
#include "defines.h"
#include "tipos.h"
/* tipos de formatos y modos de direccionamiento */
#define SINOPERANDOS 0 /* formato de 1 byte sin operandos */
#define PREFIJOS 1 /* formato de 1 byte sin operandos que es un prefijo */
#define REGPALABRA 2 /* formato de 1 byte: 1 operando registro palabra */
#define REGSEGMENTO 3 /* formato de 1 byte: 1 operando reg. segmento */
#define REGMEM 4 /* hasta 4 bytes; 1 operando reg/mem */
#define INMED8 5 /* formato de 2 bytes: 1 operando inm8 */
#define INMED16 6 /* formato de 3 bytes: 1 operando inm16 */
#define SALTO8 7 /* formato de 2 bytes: 1 operando: relativo IP 8bits */
#define SALTO16 8 /* formato de 3 bytes: 1 operando: relativo IP 16bits */
#define BASEOFFSET 9 /* formato de 5 bytes: 1 op: BASE:OFFSET (CALL y JMP) */
#define REGULAR 10 /* hasta 4 bytes; 2 operandos reg/mem -> reg/mem */
#define INMEDTOAX 11 /* hasta 3 bytes; 2 operandos inm -> acc */
#define INMEDTOREGMEM 12 /* hasta 6 bytes; 2 operandos inm -> reg/mem */
#define MOVMEMAX 13 /* formato de 3 bytes; 2 op LOAD/STORE mem-AX */
#define MOVSEGMTO 14 /* hasta 4 bytes; 2 op MOV entre reg/mem y reg. seg. */
#define MOVINMEDTOREG 15 /* hasta 3 bytes; 2 operandos MOV inm -> registro */
#define DESPLAZAMIENTO 16 /* hasta 4 bytes; 2 op reg/mem y contador (1 o CL) */
#define ENTRADA_SALIDA 17 /* hasta 2 bytes: 2 operandos: acc y DX o inm8 */
void OperandoRegistro(char w, char codigo, char *registro)
{
char *registrosL[] = {"AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH"};
char *registrosX[] = {"AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI"};
switch(w)
{
case 0:
sprintf(registro, registrosL[codigo]);
break;
case 1:
sprintf(registro, registrosX[codigo]);
break;
}
}
void OperandoRegSeg(char codigo, char *registro)
{
char *regSEG[] = {"ES", "CS", "SS", "DS"};
sprintf(registro, regSEG[codigo]);
}
void OperandoMemoria(char codigo, char *memoria)
{
/* char *direfectiva[] = {"[BX][SI]", "[BX][DI]", "[BP][SI]", "[BP][DI]",
"[SI]", "[DI]", "[BP]", "[BX]"}; */
/* cambio los identificadores de las ubicaciones de memoria para simplificar el análisis */
char *direfectiva[] = {"[BXSI]", "[BXDI]", "[BPSI]", "[BPDI]",
"[SI]", "[DI]", "[BP]", "[BX]"};
sprintf(memoria, direfectiva[codigo]);
}
void OperandoRM(char w, char mod, char r_m, unsigned char byteL, unsigned char byteH, char *registro_memoria, char *l)
{
char desplazamiento[5];
switch(mod)
{
case 3: /* el operando es un registro */
OperandoRegistro(w, r_m, registro_memoria); *l=0;
break;
case 0:
/* el operando es memoria sin desplazamiento */
if(r_m!=6) {OperandoMemoria(r_m, registro_memoria); *l=0;}
/* el operando es una dirección absoluta de memoria */
else {sprintf(registro_memoria, "[%02X%02X]", byteH, byteL); *l=2;}
break;
case 1: /* el operando es memoria con desplazamiento 8 */
OperandoMemoria(r_m, registro_memoria);
sprintf(desplazamiento, "%02X", byteL); *l=1;
strcat(registro_memoria, desplazamiento);
break;
case 2: /* el operando es memoria con desplazamiento 16 */
OperandoMemoria(r_m, registro_memoria);
sprintf(desplazamiento, "%02X%02X", byteH, byteL); *l=2;
strcat(registro_memoria, desplazamiento);
break;
}
}
void DecodificarInstruccion086(unsigned char formato[6], struct desensamblado *instruccion)
{
char *saltos_cc[] = {"JO", "JNO", "JB/JNAE", "JNB/JAE", "JE/JZ",
"JNE/JNZ", "JBE/JNA", "JNBE/JA", "JS", "JNS",
"JP/JPE", "JNP/JPO", "JL/JNGE", "JNL/JGE",
"JLE/JNG", "JNLE/JG"};
char *tablainmediatos[] = {"ADD", "OR", "ADC", "SBB", "AND",
"SUB", "XOR", "CMP"};
char *tabladesplazamientos[] = {"ROL", "ROR", "RCL", "RCR",
"SHL/SAL", "SHR", "(086)?", "SAR"};
char *tablagrupo1[] = {"TEST", "(086)?", "NOT", "NEG", "MUL",
"IMUL", "DIV", "IDIV"};
char *tablagrupo2[] = {"INC", "DEC", "CALL", "CALL", "JMP",
"JMP", "PUSH", "(086)?"};
char nemonico[20] = {""};
char op1[20] = {""};
char op2[20] = {""};
char modo = SINOPERANDOS;
char longitud = 0;
char bytesadicionales = 0;
union{
struct{
unsigned short int valor;
}byte;
struct{
unsigned int L:4;
unsigned int H:4;
}nibble;
struct{
unsigned int w:1;
unsigned int d:1;
unsigned int opcode:6;
}campo;
}byte1;
union{
struct{
unsigned short int valor;
}byte;
struct{
unsigned int r_m:3;
unsigned int reg:3;
unsigned int mod:2;
}campo;
}byte2;
byte1.byte.valor = formato[0]; /* primer byte del formato */
byte2.byte.valor = formato[1]; /* segundo byte del formato */
longitud = 1; /* al menos leo el primer byte del formato */
switch(byte1.nibble.H)
{
case 0x0:
switch(byte1.nibble.L)
{
case 0x0:
case 0x1:
case 0x2:
case 0x3:
sprintf(nemonico, "ADD"); modo = REGULAR; break;
case 0x4:
case 0x5:
sprintf(nemonico, "ADD"); modo = INMEDTOAX; break;
case 0x6:
sprintf(nemonico, "PUSH"); modo = REGSEGMENTO; break;
case 0x7:
sprintf(nemonico, "POP"); modo = REGSEGMENTO; break;
case 0x8:
case 0x9:
case 0xA:
case 0xB:
sprintf(nemonico, "OR"); modo = REGULAR; break;
case 0xC:
case 0xD:
sprintf(nemonico, "OR"); modo = INMEDTOAX; break;
case 0xE:
sprintf(nemonico, "PUSH"); modo = REGSEGMENTO; break;
case 0xF: /* esta instrucción no existe realmente */
sprintf(nemonico, "POP"); modo = REGSEGMENTO; break;
}
break;
case 0x1:
switch(byte1.nibble.L)
{
case 0x0:
case 0x1:
case 0x2:
case 0x3:
sprintf(nemonico, "ADC"); modo = REGULAR; break;
case 0x4:
case 0x5:
sprintf(nemonico, "ADC"); modo = INMEDTOAX; break;
case 0x6:
sprintf(nemonico, "PUSH"); modo = REGPALABRA; break;
case 0x7:
sprintf(nemonico, "POP"); modo = REGPALABRA; break;
case 0x8:
case 0x9:
case 0xA:
case 0xB:
sprintf(nemonico, "SBB"); modo = REGULAR; break;
case 0xC:
case 0xD:
sprintf(nemonico, "SBB"); modo = INMEDTOAX; break;
case 0xE:
sprintf(nemonico, "PUSH"); modo = REGPALABRA; break;
case 0xF:
sprintf(nemonico, "POP"); modo = REGPALABRA; break;
}
break;
case 0x2:
switch(byte1.nibble.L)
{
case 0x0:
case 0x1:
case 0x2:
case 0x3:
sprintf(nemonico, "AND"); modo = REGULAR; break;
case 0x4:
case 0x5:
sprintf(nemonico, "AND"); modo = INMEDTOAX; break;
case 0x6:
sprintf(nemonico, "ES"); modo = PREFIJOS; break;
case 0x7:
sprintf(nemonico, "DAA"); modo = SINOPERANDOS; break;
case 0x8:
case 0x9:
case 0xA:
case 0xB:
sprintf(nemonico, "SUB"); modo = REGULAR; break;
case 0xC:
case 0xD:
sprintf(nemonico, "SUB"); modo = INMEDTOAX; break;
case 0xE:
sprintf(nemonico, "CS"); modo = PREFIJOS; break;
case 0xF:
sprintf(nemonico, "DAS"); modo = SINOPERANDOS; break;
}
break;
case 0x3:
switch(byte1.nibble.L)
{
case 0x0:
case 0x1:
case 0x2:
case 0x3:
sprintf(nemonico, "XOR"); modo = REGULAR; break;
case 0x4:
case 0x5:
sprintf(nemonico, "XOR"); modo = INMEDTOAX; break;
case 0x6:
sprintf(nemonico, "SS"); modo = PREFIJOS; break;
case 0x7:
sprintf(nemonico, "AAA"); modo = SINOPERANDOS; break;
case 0x8:
case 0x9:
case 0xA:
case 0xB:
sprintf(nemonico, "CMP"); modo = REGULAR; break;
case 0xC:
case 0xD:
sprintf(nemonico, "CMP"); modo = INMEDTOAX; break;
case 0xE:
sprintf(nemonico, "DS"); modo = PREFIJOS; break;
case 0xF:
sprintf(nemonico, "AAS"); modo = SINOPERANDOS; break;
}
break;
case 0x4:
if(byte1.nibble.L < 8)
sprintf(nemonico, "INC");
else
sprintf(nemonico, "DEC");
modo = REGPALABRA;
break;
case 0x5:
if(byte1.nibble.L < 8) sprintf(nemonico, "PUSH");
else sprintf(nemonico, "POP");
modo = REGPALABRA;
break;
case 0x6:
sprintf(nemonico, "(086)?");
modo = SINOPERANDOS;
break;
case 0x7:
sprintf(nemonico, saltos_cc[byte1.nibble.L]);
modo = SALTO8;
break;
case 0x8:
switch(byte1.nibble.L)
{
case 0x0: /* requiere 2º byte */
case 0x1:
case 0x2:
case 0x3: /* binario 1000 00 XX; grupo inmediatos */
/* aunque necesito el 2º byte del formato no lo cuanto ahora */
/* lo contaré después cuando obtenga el operando del 2º byte */
sprintf(nemonico, tablainmediatos[byte2.campo.reg]);
modo = INMEDTOREGMEM;
break;
case 0x4:
case 0x5:
sprintf(nemonico, "TEST"); modo = REGULAR; break;
case 0x6:
case 0x7:
sprintf(nemonico, "XCHG"); modo = REGULAR; break;
case 0x8:
case 0x9:
case 0xA:
case 0xB:
sprintf(nemonico, "MOV"); modo = REGULAR; break;
case 0xC:
case 0xE:
sprintf(nemonico, "MOV"); modo = MOVSEGMTO; break;
case 0xD:
sprintf(nemonico, "LEA");
modo = REGULAR; /* CON */ byte1.campo.d = 1; byte1.campo.w = 1;
break;
case 0xF:
sprintf(nemonico, "POP"); modo = REGMEM; break;
}
break;
case 0x9:
switch(byte1.nibble.L)
{
case 0x0:
sprintf(nemonico, "NOP"); modo = SINOPERANDOS; break;
case 0x8:
sprintf(nemonico, "CBW"); modo = SINOPERANDOS; break;
case 0x9:
sprintf(nemonico, "CWD"); modo = SINOPERANDOS; break;
case 0xA:
sprintf(nemonico, "CALL"); modo = BASEOFFSET; break;
case 0xB:
sprintf(nemonico, "WAIT"); modo = SINOPERANDOS; break;
case 0xC:
sprintf(nemonico, "PUSHF"); modo = SINOPERANDOS; break;
case 0xD:
sprintf(nemonico, "POPF"); modo = SINOPERANDOS; break;
case 0xE:
sprintf(nemonico, "SAHF"); modo = SINOPERANDOS; break;
case 0xF:
sprintf(nemonico, "LAHF"); modo = SINOPERANDOS; break;
default:
sprintf(nemonico, "XCHG"); modo = REGPALABRA;
}
break;
case 0xA:
switch(byte1.nibble.L)
{
case 0x0:
case 0x1:
case 0x2:
case 0x3:
sprintf(nemonico, "MOV"); modo = MOVMEMAX; break;
case 0x4:
case 0x5:
sprintf(nemonico, "MOVS"); modo = SINOPERANDOS; break;
case 0x6:
case 0x7:
sprintf(nemonico, "CMPS"); modo = SINOPERANDOS; break;
case 0x8:
case 0x9:
sprintf(nemonico, "TEST"); modo = INMEDTOAX; break;
case 0xA:
case 0xB:
sprintf(nemonico, "STOS"); modo = SINOPERANDOS; break;
case 0xC:
case 0xD:
sprintf(nemonico, "LODS"); modo = SINOPERANDOS; break;
case 0xE:
case 0xF:
sprintf(nemonico, "SCAS"); modo = SINOPERANDOS; break;
}
break;
case 0xB:
sprintf(nemonico, "MOV"); modo = MOVINMEDTOREG; break;
case 0xC:
switch(byte1.nibble.L)
{
case 0x0:
case 0x1:
case 0x8:
case 0x9:
sprintf(nemonico, "(086)?"); modo = SINOPERANDOS; break;
case 0x2:
sprintf(nemonico, "RET"); modo = INMED16; break;
case 0x3:
sprintf(nemonico, "RET"); modo = SINOPERANDOS; break;
case 0xA:
sprintf(nemonico, "RETF"); modo = INMED16; break;
case 0xB:
sprintf(nemonico, "RETF"); modo = SINOPERANDOS; break;
break;
case 0x4:
sprintf(nemonico, "LES");
modo = REGULAR; /* CON */ byte1.campo.d = 1; byte1.campo.w = 1;
break;
case 0x5:
sprintf(nemonico, "LDS");
modo = REGULAR; /* CON */ byte1.campo.d = 1; byte1.campo.w = 1;
break;
case 0x6:
case 0x7:
sprintf(nemonico, "MOV"); modo = INMEDTOREGMEM; break;
case 0xC:
sprintf(nemonico, "INT 3"); modo = SINOPERANDOS; break;
case 0xD:
sprintf(nemonico, "INT"); modo = INMED8; break;
case 0xE:
sprintf(nemonico, "INTO"); modo = SINOPERANDOS; break;
case 0xF:
sprintf(nemonico, "IRET"); modo = SINOPERANDOS; break;
}
break;
case 0xD:
switch(byte1.nibble.L)
{
case 0x00: /* requiere 2º byte */
case 0x01:
case 0x02:
case 0x03: /* binario 1101 00 XX; grupo desplazamientos */
/* aunque necesito el 2º byte del formato lo contaré cuando lea el operando */
sprintf(nemonico, tabladesplazamientos[byte2.campo.reg]);
modo = DESPLAZAMIENTO;
break;
case 0x04:
sprintf(nemonico, "AAM"); modo = INMED8; break;
case 0x05:
sprintf(nemonico, "AAD"); modo = INMED8; break;
case 0x06:
sprintf(nemonico, "(086)?"); modo = SINOPERANDOS; break;
case 0x07:
sprintf(nemonico, "XLAT"); modo = SINOPERANDOS; break;
default:
sprintf(nemonico, "ESC"); modo = REGMEM;
}
break;
case 0xE:
switch(byte1.nibble.L)
{
case 0x0:
sprintf(nemonico, "LOOPNZ/LOOPNE"); modo = SALTO8; break;
case 0x1:
sprintf(nemonico, "LOOPZ/LOOPE"); modo = SALTO8; break;
case 0x2:
sprintf(nemonico, "LOOP"); modo = SALTO8; break;
case 0x3:
sprintf(nemonico, "JCXZ"); modo = SALTO8; break;
case 0x4:
case 0x5:
case 0xC:
case 0xD:
sprintf(nemonico, "IN"); modo = ENTRADA_SALIDA; break;
case 0x6:
case 0x7:
case 0xE:
case 0xF:
sprintf(nemonico, "OUT"); modo = ENTRADA_SALIDA; break;
case 0x8:
sprintf(nemonico, "CALL"); modo = SALTO16; break;
case 0x9:
sprintf(nemonico, "JMP"); modo = SALTO16; break;
case 0xA:
sprintf(nemonico, "JMP"); modo = BASEOFFSET; break;
case 0xB:
sprintf(nemonico, "JMP"); modo = SALTO8; break;
}
break;
case 0xF:
switch(byte1.nibble.L)
{
case 0x0:
sprintf(nemonico, "LOCK"); modo = SINOPERANDOS; break;
case 0x1:
sprintf(nemonico, "(086)?"); modo = SINOPERANDOS; break;
case 0x2: /* este nemónico es equivalente a "REPZ/REPE" */
sprintf(nemonico, "REP"); modo = PREFIJOS; break;
case 0x3:
sprintf(nemonico, "REPNZ/REPNE"); modo = PREFIJOS; break;
case 0x4:
sprintf(nemonico, "HLT"); modo = SINOPERANDOS; break;
case 0x5:
sprintf(nemonico, "CMC"); modo = SINOPERANDOS; break;
case 0x6: /* requiere 2º byte */
case 0x7: /* binario 1111 01 1X; grupo 1 */
/* aunque necesito el 2º byte del formato no lo cuento ahora */
/* lo contaré cuando leo el operando del 2º byte */
sprintf(nemonico, tablagrupo1[byte2.campo.reg]);
switch(byte2.campo.reg)
{
case 0: /* instrucción TEST */
modo = INMEDTOREGMEM;
break;
case 1: /* no definida (086)? */
modo = SINOPERANDOS;
break;
case 2: /* instrucción NOT */
case 3: /* instrucción NEG */
case 4: /* instrucción MUL */
case 5: /* instrucción IMUL */
case 6: /* instrucción DIV */
case 7: /* instrucción IDIV */
modo = REGMEM;
break;
}
break;
case 0x8:
sprintf(nemonico, "CLC"); modo = SINOPERANDOS; break;
case 0x9:
sprintf(nemonico, "STC"); modo = SINOPERANDOS; break;
case 0xA:
sprintf(nemonico, "CLI"); modo = SINOPERANDOS; break;
case 0xB:
sprintf(nemonico, "STI"); modo = SINOPERANDOS; break;
case 0xC:
sprintf(nemonico, "CLD"); modo = SINOPERANDOS; break;
case 0xD:
sprintf(nemonico, "STD"); modo = SINOPERANDOS; break;
case 0xE: /* requiere 2º byte */
case 0xF: /* binario 1111 11 1X; grupo 2 */
/* aunque necesito el 2º byte del formato lo contaré cuando saque el operando */
sprintf(nemonico, tablagrupo2[byte2.campo.reg]);
switch(byte2.campo.reg)
{
case 0: /* instrucción INC */
case 1: /* instrucción DEC */
case 2:
case 3: /* instrucciones CALL */
case 4:
case 5: /* instrucciones JMP */
case 6: /* instrucción PUSH */
modo = REGMEM;
break;
case 7:
modo = SINOPERANDOS; /* no definida (086)? */
break;
}
break;
}
break;
}
/* ahora añado los operandos (si los hay) al nemónico */
/* quizá sea interesante dar un formato que permita distinguir con más facilidad */
/* el tipo de operando (registro, memoria, inmediato, etc.) con el fin de */
/* facilitar el análisis posterior por funciones de los operandos */
/* cuando hay un único operando siempre se considera op1 (destino en la notación INTEL) */
switch (modo)
{
case SINOPERANDOS: /* sin operandos */
case PREFIJOS:
break;
case REGPALABRA: /* 1 operando: registro tamaño palabra */
OperandoRegistro(1, byte1.nibble.L & 0x7, op1);
break;
case REGSEGMENTO: /* 1 operando registro segmento */
OperandoRegSeg((byte1.campo.opcode >> 1) & 0x03, op1);
break;
case REGMEM: /* 1 operando registro o memoria */
longitud += 1; /* necesito el 2º byte */
OperandoRM(byte1.campo.w, byte2.campo.mod, byte2.campo.r_m, formato[longitud], formato[longitud+1], op1, &bytesadicionales);
longitud += bytesadicionales; /* sumo los posibles bytes del formato utilizados */
break;
case INMED8: /* 1 operando inmediato de 8 bits */
longitud += 1; /* necesito otro byte más */
if(!strcmp(nemonico, "INT")) sprintf(op1, "%02X", formato[longitud-1]);
/* en los casos de AAM y AAD el 2º byte es 0x0A y sólo hay que contarlo */
break;
case INMED16: /* 1 operando inmediato de 16 bits */
longitud += 2; /* necesito otros 2 bytes más */
sprintf(op1, "%02X%02X", formato[longitud-1], formato[longitud-2]);
break;
case SALTO8: /* 1 operando: byte */
longitud += 1; /* necesito otro byte más */
/* sprintf(destino, "IP+%02X", formato[longitud-1]); */
/* no hace falta dar IP ya que es un implícito indicado en la base de datos */
sprintf(op1, "%02X", formato[longitud-1]);
break;
case SALTO16: /* 1 operando: 2 bytes */
longitud += 2; /* necesito otros 2 bytes más */
/* sprintf(destino, "IP+%02X%02X", formato[longitud-1], formato[longitud-2]); */
/* no hace falta dar IP ya que es un implícito indicado en la base de datos */
sprintf(op1, "%02X%02X", formato[longitud-1], formato[longitud-2]);
break;
case BASEOFFSET: /* 1 operando: base:offset */
longitud += 4; /* necesito otros 4 bytes más */
sprintf(op1, "%02X%02X:%02X%02X", formato[longitud-1], formato[longitud-2], formato[longitud-3], formato[longitud-4]);
break;
case REGULAR: /* 2 operandos: 1 registro y 1 reg/mem */
longitud += 1; /* necesito el 2º byte */
switch(byte1.campo.d)
{
case 0: /* reg es el operando 2 (fuente) */
OperandoRegistro(byte1.campo.w, byte2.campo.reg, op2);
OperandoRM(byte1.campo.w, byte2.campo.mod, byte2.campo.r_m, formato[longitud], formato[longitud+1], op1, &bytesadicionales);
break;
case 1: /* reg es el operando 1 (destino) */
OperandoRegistro(byte1.campo.w, byte2.campo.reg, op1);
OperandoRM(byte1.campo.w, byte2.campo.mod, byte2.campo.r_m, formato[longitud], formato[longitud+1], op2, &bytesadicionales);
break;
}
longitud += bytesadicionales; /* sumo los posibles bytes del formato utilizados */
break;
case INMEDTOAX: /* 2 operandos: inmediato -> acumulador */
switch(byte1.campo.w)
{
case 0:
longitud += 1; /* necesito otro byte más */
sprintf(op2, "%02X", formato[longitud-1]);
sprintf(op1, "AL"); /* este op1 está asociado a la operación (es implícito) */
/* sin embargo no lo considero tal ya que el programador */
/* lo explicita voluntariamente cuando escribe la instrucción */
/* el formato lo hace implícito para ahorrar espacio */
break;
case 1:
longitud += 2; /* necesito otros 2 bytes más */
sprintf(op2, "%02X%02X", formato[longitud-1], formato[longitud-2]);
sprintf(op1, "AX");
break;
}
break;
case INMEDTOREGMEM: /* 2 operandos: inmediato -> registro o memoria */
longitud += 1; /* necesito el 2º byte */
OperandoRM(byte1.campo.w, byte2.campo.mod, byte2.campo.r_m, formato[longitud], formato[longitud+1], op1, &bytesadicionales);
longitud += bytesadicionales; /* sumo los posibles bytes del formato utilizados */
switch(byte1.campo.w)
{
case 0:
longitud += 1; /* necesito otro byte más */
sprintf(op2, "%02X", formato[longitud-1]);
break;
case 1:
longitud += 2; /* necesito otros 2 bytes más */
sprintf(op2, "%02X%02X", formato[longitud-1], formato[longitud-2]);
break;
}
break;
case MOVMEMAX: /* 2 operandos: load/store entre memoria y acc */
longitud += 2; /* necesito otros 2 bytes más */
switch(byte1.campo.d)
{
case 0: /* memoria es el operando 2 */
sprintf(op2, "[%02X%02X]", formato[longitud-1], formato[longitud-2]);
OperandoRegistro(byte1.campo.w, 0, op1); /* es el acumulador */
break;
case 1: /* memoria es el operando 1 */
sprintf(op1, "[%02X%02X]", formato[longitud-1], formato[longitud-2]);
OperandoRegistro(byte1.campo.w, 0, op2); /* es el acumulador */
/* este op1 está asociado a la operación (es implícito) */
/* sin embargo no lo considero tal ya que el programador */
/* lo explicita voluntariamente cuando escribe la instrucción */
/* el formato lo hace implícito para ahorrar espacio */
break;
}
break;
case MOVSEGMTO: /* 2 operandos: 1 reg. de segmento y 1 reg/mem */
longitud += 1; /* necesito el 2º byte */
switch(byte1.campo.d)
{
case 0: /* reg. de segmento es el operando 2 */
OperandoRegSeg(byte2.campo.reg & 0x3, op2);
OperandoRM(1, byte2.campo.mod, byte2.campo.r_m, formato[longitud], formato[longitud+1], op1, &bytesadicionales);
/* hay que forzar w = 1 ya que del formato viene a 0 */
break;
case 1: /* reg. de segmento es el operando 1 */
OperandoRegSeg(byte2.campo.reg & 0x3, op1);
OperandoRM(1, byte2.campo.mod, byte2.campo.r_m, formato[longitud], formato[longitud+1], op2, &bytesadicionales);
/* hay que forzar w = 1 ya que del formato viene a 0 */
break;
}
longitud += bytesadicionales; /* sumo los posibles bytes del formato utilizados */
break;
case MOVINMEDTOREG: /* 2 operandos: inm -> registro */
switch((byte1.nibble.L & 0x8) >> 3)
{
case 0:
longitud += 1; /* necesito otro byte más */
sprintf(op2, "%02X", formato[longitud-1]);
OperandoRegistro(0, byte1.nibble.L & 0x7, op1);
break;
case 1:
longitud += 2; /* necesito otros 2 bytes más */
sprintf(op2, "%02X%02X", formato[longitud-1], formato[longitud-2]);
OperandoRegistro(1, byte1.nibble.L & 0x7, op1);
break;
}
break;
case DESPLAZAMIENTO: /* 2 operandos: reg/mem y contador */
longitud += 1; /* necesito el 2º byte */
OperandoRM(byte1.campo.w, byte2.campo.mod, byte2.campo.r_m, formato[longitud], formato[longitud+1], op1, &bytesadicionales);
longitud += bytesadicionales; /* sumo los posibles bytes del formato utilizados */
switch(byte1.campo.d) /* ahora se llama 'v' en lugar de 'd' pero es el mismo */
{
case 0:
sprintf(op2, "01"); /* todos los inmediatos deben tener 2 dígitos hex por byte */
break;
case 1:
sprintf(op2, "CL");
break;
}
break;
case ENTRADA_SALIDA: /* 2 operandos: acc y DX o inm8 */
switch(byte1.campo.d)
{
case 0: /* reg es el operando 2 */
if(byte1.campo.opcode == 57) /* 111 001 */
{
longitud += 1; /* necesito otro byte más */
sprintf(op2, "%02X", formato[longitud-1]);
}
else sprintf(op2, "DX");
OperandoRegistro(byte1.campo.w, 0, op1); /* es el acumulador */
break;
case 1: /* reg es el operando 1 */
OperandoRegistro(byte1.campo.w, 0, op2); /* es el acumulador */
if(byte1.campo.opcode == 57) /* 111 011 */
{
longitud += 1; /* necesito otro byte más */
sprintf(op1, "%02X", formato[longitud-1]);
}
else sprintf(op1, "DX");
break;
}
break;
}
/* (*p).miembro es equivalente a p->miembro */
strcpy((*instruccion).nemonico, nemonico);
strcpy(instruccion->op2, op2);
strcpy(instruccion->op1, op1);
instruccion->longitud = longitud;
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>