| /* |
| * Copyright 2002-2003 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| * CA 95054 USA or visit www.sun.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<oldName.length(); index++) { |
| switch (oldName.charAt(index)) { |
| case 'C': /* For jcxz/jecxz */ |
| if (addrSize) |
| newName.setCharAt(index, 'e'); |
| index++; |
| break; |
| case 'N': |
| if ((prefixes & PREFIX_FWAIT) == 0) |
| newName.setCharAt(index, 'n'); |
| index++; |
| break; |
| case 'S': |
| /* operand size flag */ |
| if (operandSize == true) |
| newName.setCharAt(index, 'l'); |
| else |
| newName.setCharAt(index, 'w'); |
| index++; |
| break; |
| default: |
| break; |
| } |
| } |
| return newName.toString(); |
| } |
| |
| //IA-32 Intel Architecture Software Developer's Manual Volume 2 |
| //Refer to Chapter 2 - Instruction Format |
| |
| //Get the Operand object from the address type and the operand type |
| private Operand getOperand(byte[] bytesArray, int addrMode, int operandType, boolean operandSize, boolean addrSize) { |
| Operand op = null; |
| switch(addrMode) { |
| case ADDR_E: |
| case ADDR_W: //SSE: ModR/M byte specifies either 128 bit XMM register or memory |
| case ADDR_Q: //SSE: ModR/M byte specifies either 128 bit MMX register or memory |
| X86SegmentRegister segReg = getSegmentRegisterFromPrefix(prefixes); |
| |
| if (mod == 3) { //Register operand, no SIB follows |
| if (addrMode == ADDR_E) { |
| switch (operandType) { |
| case b_mode: |
| op = X86Registers.getRegister8(rm); |
| break; |
| case w_mode: |
| op = X86Registers.getRegister16(rm); |
| break; |
| case v_mode: |
| if (operandSize == true) //Operand size prefix is present |
| op = X86Registers.getRegister32(rm); |
| else |
| op = X86Registers.getRegister16(rm); |
| break; |
| case p_mode: |
| X86Register reg; |
| if (operandSize == true) //Operand size prefix is present |
| reg = X86Registers.getRegister32(rm); |
| else |
| reg = X86Registers.getRegister16(rm); |
| |
| op = new X86RegisterIndirectAddress(segReg, reg, null, 0); |
| break; |
| default: |
| break; |
| } |
| } else if (addrMode == ADDR_W) { |
| op = X86XMMRegisters.getRegister(rm); |
| } else if (addrMode == ADDR_Q) { |
| op = X86MMXRegisters.getRegister(rm); |
| } |
| |
| } else { //mod != 3 |
| //SIB follows for (rm==4), SIB gives scale, index and base in this case |
| //disp32 is present for (mod==0 && rm==5) || (mod==2) |
| //disp8 is present for (mod==1) |
| //for (rm!=4) base is register at rm. |
| int scale = 0; |
| int index = 0; |
| int base = 0; |
| long disp = 0; |
| if(rm == 4) { |
| int sib = readByte(bytesArray, byteIndex); |
| byteIndex++; |
| scale = (sib >> 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; |
| } |
| |
| } |