/* * Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, * CA 94065 USA or visit www.oracle.com if you need additional information or * have any questions. * */ package sun.jvm.hotspot.asm.x86; import sun.jvm.hotspot.asm.*; // basic instruction decoder class public class InstructionDecoder implements /* imports */ X86Opcodes , RTLDataTypes, RTLOperations { protected String name; protected int addrMode1; protected int operandType1; protected int addrMode2; protected int operandType2; protected int addrMode3; protected int operandType3; private int mod; private int regOrOpcode; private int rm; protected int prefixes; protected int byteIndex; protected int instrStartIndex; public InstructionDecoder(String name) { this.name = name; this.operandType1 = INVALID_OPERANDTYPE; this.operandType2 = INVALID_OPERANDTYPE; this.operandType3 = INVALID_OPERANDTYPE; this.addrMode1 = INVALID_ADDRMODE; this.addrMode2 = INVALID_ADDRMODE; this.addrMode3 = INVALID_ADDRMODE; } public InstructionDecoder(String name, int addrMode1, int operandType1) { this(name); this.addrMode1 = addrMode1; this.operandType1 = operandType1; } public InstructionDecoder(String name, int addrMode1, int operandType1, int addrMode2, int operandType2) { this(name, addrMode1, operandType1); this.addrMode2 = addrMode2; this.operandType2 = operandType2; } public InstructionDecoder(String name, int addrMode1, int operandType1, int addrMode2, int operandType2, int addrMode3, int operandType3) { this(name, addrMode1, operandType1, addrMode2, operandType2); this.addrMode3 = addrMode3; this.operandType3 = operandType3; } // "operand1" protected Operand getOperand1(byte[] bytesArray, boolean operandSize, boolean addrSize) { if( (addrMode1 != INVALID_ADDRMODE) && (operandType1 != INVALID_OPERANDTYPE) ) return getOperand(bytesArray, addrMode1, operandType1, operandSize, addrSize); else return null; } // "operand2" protected Operand getOperand2(byte[] bytesArray, boolean operandSize, boolean addrSize) { if( (addrMode2 != INVALID_ADDRMODE) && (operandType2 != INVALID_OPERANDTYPE) ) return getOperand(bytesArray, addrMode2, operandType2, operandSize, addrSize); else return null; } // "operand3" protected Operand getOperand3(byte[] bytesArray, boolean operandSize, boolean addrSize) { if( (addrMode3 != INVALID_ADDRMODE) && (operandType3 != INVALID_OPERANDTYPE) ) return getOperand(bytesArray, addrMode3, operandType3, operandSize, addrSize); else return null; } static int readInt32(byte[] bytesArray, int index) { int ret = 0; ret = readByte(bytesArray, index); ret |= readByte(bytesArray, index+1) << 8; ret |= readByte(bytesArray, index+2) << 16; ret |= readByte(bytesArray, index+3) << 24; return ret; } static int readInt16(byte[] bytesArray, int index) { int ret = 0; ret = readByte(bytesArray, index); ret |= readByte(bytesArray, index+1) << 8; return ret; } static int readByte(byte[] bytesArray, int index) { int ret = 0; if (index < bytesArray.length) { ret = (int)bytesArray[index]; ret = ret & 0xff; } return ret; } private boolean isModRMPresent(int addrMode) { if( (addrMode == ADDR_E) || (addrMode == ADDR_G) || (addrMode == ADDR_FPREG) || (addrMode == ADDR_Q) || (addrMode == ADDR_W) ) return true; else return false; } public int getCurrentIndex() { return byteIndex; } public Instruction decode(byte[] bytesArray, int index, int instrStartIndex, int segmentOverride, int prefixes, X86InstructionFactory factory) { this.byteIndex = index; this.instrStartIndex = instrStartIndex; this.prefixes = prefixes; boolean operandSize; //operand-size prefix boolean addrSize; //address-size prefix if ( ( (prefixes & PREFIX_DATA) ^ segmentOverride ) == 1) operandSize = true; else operandSize = false; if ( ((prefixes & PREFIX_ADR) ^ segmentOverride) == 1) addrSize = true; else addrSize = false; this.name = getCorrectOpcodeName(name, prefixes, operandSize, addrSize); //Fetch the mod/reg/rm byte only if it is present. if( isModRMPresent(addrMode1) || isModRMPresent(addrMode2) || isModRMPresent(addrMode3) ) { int ModRM = readByte(bytesArray, byteIndex); byteIndex++; mod = (ModRM >> 6) & 3; regOrOpcode = (ModRM >> 3) & 7; rm = ModRM & 7; } return decodeInstruction(bytesArray, operandSize, addrSize, factory); } protected Instruction decodeInstruction(byte[] bytesArray, boolean operandSize, boolean addrSize, X86InstructionFactory factory) { Operand op1 = getOperand1(bytesArray, operandSize, addrSize); Operand op2 = getOperand2(bytesArray, operandSize, addrSize); Operand op3 = getOperand3(bytesArray, operandSize, addrSize); int size = byteIndex - instrStartIndex; return factory.newGeneralInstruction(name, op1, op2, op3, size, prefixes); } // capital letters in template are macros private String getCorrectOpcodeName(String oldName, int prefixes, boolean operandSize, boolean addrSize) { StringBuffer newName = new StringBuffer(oldName); int index = 0; for(index=0; index> 6) & 3; index = (sib >> 3) & 7; base = sib & 7; } switch (mod) { case 0: switch(rm) { case 4: if(base == 5) { disp = readInt32(bytesArray, byteIndex); byteIndex += 4; if (index != 4) { op = new X86RegisterIndirectAddress(segReg, null, X86Registers.getRegister32(index), disp, scale); } else { op = new X86RegisterIndirectAddress(segReg, null, null, disp, scale); } } else { if (index != 4) { op = new X86RegisterIndirectAddress(segReg, X86Registers.getRegister32(base), X86Registers.getRegister32(index), 0, scale); } else { op = new X86RegisterIndirectAddress(segReg, X86Registers.getRegister32(base), null, 0, scale); } } break; case 5: disp = readInt32(bytesArray, byteIndex); byteIndex += 4; //Create an Address object only with displacement op = new X86RegisterIndirectAddress(segReg, null, null, disp); break; default: base = rm; //Create an Address object only with base op = new X86RegisterIndirectAddress(segReg, X86Registers.getRegister32(base), null, 0); break; } break; case 1: disp = (byte)readByte(bytesArray, byteIndex); byteIndex++; if (rm !=4) { base = rm; //Address with base and disp only op = new X86RegisterIndirectAddress(segReg, X86Registers.getRegister32(base), null, disp); } else { if (index != 4) { op = new X86RegisterIndirectAddress(segReg, X86Registers.getRegister32(base), X86Registers.getRegister32(index), disp, scale); } else { op = new X86RegisterIndirectAddress(segReg, X86Registers.getRegister32(base), null, disp, scale); } } break; case 2: disp = readInt32(bytesArray, byteIndex); byteIndex += 4; if (rm !=4) { base = rm; //Address with base and disp op = new X86RegisterIndirectAddress(segReg, X86Registers.getRegister32(base), null, disp); } else if (index != 4) { op = new X86RegisterIndirectAddress(segReg, X86Registers.getRegister32(base), X86Registers.getRegister32(index), disp, scale); } else { op = new X86RegisterIndirectAddress(segReg, X86Registers.getRegister32(base), null, disp, scale); } break; } } break; case ADDR_I: switch (operandType) { case b_mode: op = new Immediate(new Integer(readByte(bytesArray, byteIndex))); byteIndex++; break; case w_mode: op = new Immediate(new Integer(readInt16(bytesArray, byteIndex))); byteIndex += 2; break; case v_mode: if (operandSize == true) { //Operand size prefix is present op = new Immediate(new Integer(readInt32(bytesArray, byteIndex))); byteIndex += 4; } else { op = new Immediate(new Integer(readInt16(bytesArray, byteIndex))); byteIndex += 2; } break; default: break; } break; case ADDR_REG: //registers switch(operandType) { case EAX: case ECX: case EDX: case EBX: case ESP: case EBP: case ESI: case EDI: if(operandSize == true) { op = X86Registers.getRegister32(operandType - EAX); } else { op = X86Registers.getRegister16(operandType - EAX); } break; case AX: case CX: case DX: case BX: case SP: case BP: case SI: case DI: op = X86Registers.getRegister16(operandType - AX); break; case AL: case CL: case DL: case BL: case AH: case CH: case DH: case BH: op = X86Registers.getRegister8(operandType - AL); break; case ES: //ES, CS, SS, DS, FS, GS case CS: case SS: case DS: case FS: case GS: op = X86SegmentRegisters.getSegmentRegister(operandType - ES); break; } break; case ADDR_DIR: //segment and offset long segment = 0; long offset = 0; switch (operandType) { case p_mode: if (addrSize == true) { offset = readInt32(bytesArray, byteIndex); byteIndex += 4; segment = readInt16(bytesArray, byteIndex); byteIndex += 2; } else { offset = readInt16(bytesArray, byteIndex); byteIndex += 2; segment = readInt16(bytesArray, byteIndex); byteIndex += 2; } op = new X86DirectAddress(segment, offset); //with offset break; case v_mode: if (addrSize == true) { offset = readInt32(bytesArray, byteIndex); byteIndex += 4; } else { offset = readInt16(bytesArray, byteIndex); byteIndex += 2; } op = new X86DirectAddress(offset); //with offset break; default: break; } break; case ADDR_G: switch (operandType) { case b_mode: op = X86Registers.getRegister8(regOrOpcode); break; case w_mode: op = X86Registers.getRegister16(regOrOpcode); break; case d_mode: op = X86Registers.getRegister32(regOrOpcode); break; case v_mode: if (operandSize == true) op = X86Registers.getRegister32(regOrOpcode); else op = X86Registers.getRegister16(regOrOpcode); break; default: break; } break; case ADDR_SEG: op = X86SegmentRegisters.getSegmentRegister(regOrOpcode); break; case ADDR_OFF: int off = 0; if (addrSize == true) { off = readInt32(bytesArray, byteIndex); byteIndex += 4; } else { off = readInt16(bytesArray, byteIndex); byteIndex += 2; } op = new X86DirectAddress((long)off); break; case ADDR_J: long disp = 0; //The effective address is Instruction pointer + relative offset switch(operandType) { case b_mode: disp = (byte)readByte(bytesArray, byteIndex); byteIndex++; break; case v_mode: if (operandSize == true) { disp = readInt32(bytesArray, byteIndex); byteIndex += 4; } else { disp = readInt16(bytesArray, byteIndex); byteIndex += 2; } //disp = disp + (byteIndex-instrStartIndex); break; } op = new X86PCRelativeAddress(disp); break; case ADDR_ESDI: op = new X86SegmentRegisterAddress(X86SegmentRegisters.ES, X86Registers.DI); break; case ADDR_DSSI: op = new X86SegmentRegisterAddress(X86SegmentRegisters.DS, X86Registers.SI); break; case ADDR_R: switch (operandType) { case b_mode: op = X86Registers.getRegister8(mod); break; case w_mode: op = X86Registers.getRegister16(mod); break; case d_mode: op = X86Registers.getRegister32(mod); break; case v_mode: if (operandSize == true) op = X86Registers.getRegister32(mod); else op = X86Registers.getRegister16(mod); break; default: break; } break; case ADDR_FPREG: switch (operandType) { case 0: op = X86FloatRegisters.getRegister(0); break; case 1: op = X86FloatRegisters.getRegister(rm); break; } break; //SSE: reg field of ModR/M byte selects a 128-bit XMM register case ADDR_V: op = X86XMMRegisters.getRegister(regOrOpcode); break; //SSE: reg field of ModR/M byte selects a 64-bit MMX register case ADDR_P: op = X86MMXRegisters.getRegister(regOrOpcode); break; } return op; } private X86SegmentRegister getSegmentRegisterFromPrefix(int prefixes) { X86SegmentRegister segRegister = null; if ( (prefixes & PREFIX_CS) != 0) segRegister = X86SegmentRegisters.CS; if ( (prefixes & PREFIX_DS) != 0) segRegister = X86SegmentRegisters.DS; if ( (prefixes & PREFIX_ES) != 0) segRegister = X86SegmentRegisters.ES; if ( (prefixes & PREFIX_FS) != 0) segRegister = X86SegmentRegisters.FS; if ( (prefixes & PREFIX_SS) != 0) segRegister = X86SegmentRegisters.SS; if ( (prefixes & PREFIX_GS) != 0) segRegister = X86SegmentRegisters.GS; return segRegister; } }