/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library 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 Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.jnasm.assembler.x86; import java.util.List; import java.util.Map; import org.jnode.assembler.Label; import org.jnode.assembler.UnresolvedObjectRefException; import org.jnode.assembler.x86.X86Assembler; import org.jnode.assembler.x86.X86Constants; import org.jnode.assembler.x86.X86Register; import org.jnode.assembler.x86.X86Register.CRX; import org.jnode.assembler.x86.X86Register.GPR; import org.jnode.assembler.x86.X86Register.SR; import org.jnode.jnasm.assembler.Address; import org.jnode.jnasm.assembler.Identifier; import org.jnode.jnasm.assembler.Instruction; import org.jnode.jnasm.assembler.InstructionUtils; import org.jnode.jnasm.assembler.Register; /** * @author Levente S\u00e1ntha (lsantha@users.sourceforge.net) */ public class X86Core extends AbstractX86Module { public static final int ADC_ISN = 0; public static final int ADD_ISN = ADC_ISN + 1; public static final int ALIGN_ISN = ADD_ISN + 1; public static final int AND_ISN = ALIGN_ISN + 1; public static final int BTS_ISN = AND_ISN + 1; public static final int CALL_ISN = BTS_ISN + 1; public static final int CDQ_ISN = CALL_ISN + 1; public static final int CLD_ISN = CDQ_ISN + 1; public static final int CLI_ISN = CLD_ISN + 1; public static final int CLTS_ISN = CLI_ISN + 1; public static final int CMP_ISN = CLTS_ISN + 1; public static final int CMPXCHG_ISN = CMP_ISN + 1; public static final int CPUID_ISN = CMPXCHG_ISN + 1; public static final int DEC_ISN = CPUID_ISN + 1; public static final int DIV_ISN = DEC_ISN + 1; public static final int FLDCW_ISN = DIV_ISN + 1; public static final int FNINIT_ISN = FLDCW_ISN + 1; public static final int FNSAVE_ISN = FNINIT_ISN + 1; public static final int FRSTOR_ISN = FNSAVE_ISN + 1; public static final int FSTCW_ISN = FRSTOR_ISN + 1; public static final int FXRSTOR_ISN = FSTCW_ISN + 1; public static final int FXSAVE_ISN = FXRSTOR_ISN + 1; public static final int HLT_ISN = FXSAVE_ISN + 1; public static final int IDIV_ISN = HLT_ISN + 1; public static final int IMUL_ISN = IDIV_ISN + 1; public static final int IN_ISN = IMUL_ISN + 1; public static final int INC_ISN = IN_ISN + 1; public static final int INT_ISN = INC_ISN + 1; public static final int IRET_ISN = INT_ISN + 1; public static final int IRETQ_ISN = IRET_ISN + 1; public static final int JA_ISN = IRETQ_ISN + 1; public static final int JAE_ISN = JA_ISN + 1; public static final int JB_ISN = JAE_ISN + 1; public static final int JBE_ISN = JB_ISN + 1; public static final int JE_ISN = JBE_ISN + 1; public static final int JG_ISN = JE_ISN + 1; public static final int JGE_ISN = JG_ISN + 1; public static final int JL_ISN = JGE_ISN + 1; public static final int JLE_ISN = JL_ISN + 1; public static final int JMP_ISN = JLE_ISN + 1; public static final int JNA_ISN = JMP_ISN + 1; public static final int JNE_ISN = JNA_ISN + 1; public static final int JNZ_ISN = JNE_ISN + 1; public static final int JZ_ISN = JNZ_ISN + 1; public static final int JECXZ_ISN = JZ_ISN + 1; public static final int LDMXCSR_ISN = JECXZ_ISN + 1; public static final int LEA_ISN = LDMXCSR_ISN + 1; public static final int LGDT_ISN = LEA_ISN + 1; public static final int LIDT_ISN = LGDT_ISN + 1; public static final int LMSW_ISN = LIDT_ISN + 1; public static final int LODSW_ISN = LMSW_ISN + 1; public static final int LOOP_ISN = LODSW_ISN + 1; public static final int LTR_ISN = LOOP_ISN + 1; public static final int MOV_ISN = LTR_ISN + 1; public static final int MOVSB_ISN = MOV_ISN + 1; public static final int MOVSW_ISN = MOVSB_ISN + 1; public static final int MOVSD_ISN = MOVSW_ISN + 1; public static final int MOVSX_ISN = MOVSD_ISN + 1; public static final int MOVZX_ISN = MOVSX_ISN + 1; public static final int MUL_ISN = MOVZX_ISN + 1; public static final int NEG_ISN = MUL_ISN + 1; public static final int NOP_ISN = NEG_ISN + 1; public static final int NOT_ISN = NOP_ISN + 1; public static final int OR_ISN = NOT_ISN + 1; public static final int OUT_ISN = OR_ISN + 1; public static final int POP_ISN = OUT_ISN + 1; public static final int POPA_ISN = POP_ISN + 1; public static final int POPF_ISN = POPA_ISN + 1; public static final int PUSH_ISN = POPF_ISN + 1; public static final int PUSHA_ISN = PUSH_ISN + 1; public static final int PUSHF_ISN = PUSHA_ISN + 1; public static final int RDMSR_ISN = PUSHF_ISN + 1; public static final int RDTSC_ISN = RDMSR_ISN + 1; public static final int RET_ISN = RDTSC_ISN + 1; public static final int SBB_ISN = RET_ISN + 1; public static final int SETE_ISN = SBB_ISN + 1; public static final int SAHF_ISN = SETE_ISN + 1; public static final int SAL_ISN = SAHF_ISN + 1; public static final int SAR_ISN = SAL_ISN + 1; public static final int SHL_ISN = SAR_ISN + 1; public static final int SETA_ISN = SHL_ISN + 1; public static final int SETAE_ISN = SETA_ISN + 1; public static final int SETB_ISN = SETAE_ISN + 1; public static final int SETBE_ISN = SETB_ISN + 1; public static final int SETNE_ISN = SETBE_ISN + 1; public static final int SHLD_ISN = SETNE_ISN + 1; public static final int SHR_ISN = SHLD_ISN + 1; public static final int SHRD_ISN = SHR_ISN + 1; public static final int STD_ISN = SHRD_ISN + 1; public static final int STI_ISN = STD_ISN + 1; public static final int STMXCSR_ISN = STI_ISN + 1; public static final int STOSB_ISN = STMXCSR_ISN + 1; public static final int STOSD_ISN = STOSB_ISN + 1; public static final int STOSQ_ISN = STOSD_ISN + 1; public static final int STOSW_ISN = STOSQ_ISN + 1; public static final int SUB_ISN = STOSW_ISN + 1; public static final int TEST_ISN = SUB_ISN + 1; public static final int WRMSR_ISN = TEST_ISN + 1; public static final int XCHG_ISN = WRMSR_ISN + 1; public static final int XOR_ISN = XCHG_ISN + 1; protected static final Map<String, Integer> INSTRUCTION_MAP; private static final String[] MNEMONICS; static { Map<String, Integer> map = InstructionUtils.getInstructionMap(X86Core.class); String[] mnemonics = InstructionUtils.getMnemonicArray(map); INSTRUCTION_MAP = map; MNEMONICS = mnemonics; } X86Core(Map<String, Label> labels, Map<String, Integer> constants) { super(labels, constants); } String[] getMnemonics() { return MNEMONICS; } public boolean emit(String mnemonic, List<Object> operands, int operandSize, Instruction instruction) { this.instruction = instruction; this.operands = operands; this.operandSize = operandSize; Integer key = INSTRUCTION_MAP.get(mnemonic); if (key == null) return false; switch (key) { case ADC_ISN: emitADC(); break; case ADD_ISN: emitADD(); break; case ALIGN_ISN: emitALIGN(); break; case AND_ISN: emitAND(); break; case BTS_ISN: emitBTS(); break; case CALL_ISN: emitCALL(); break; case CDQ_ISN: emitCDQ(); break; case CLD_ISN: emitCLD(); break; case CLI_ISN: emitCLI(); break; case CLTS_ISN: emitCLTS(); break; case CMP_ISN: emitCMP(); break; case CMPXCHG_ISN: emitCMPXCHG(); break; case CPUID_ISN: emitCPUID(); break; case DEC_ISN: emitDEC(); break; case DIV_ISN: emitDIV(); break; case FLDCW_ISN: emitFLDCW(); break; case FNINIT_ISN: emitFNINIT(); break; case FNSAVE_ISN: emitFNSAVE(); break; case FRSTOR_ISN: emitFRSTOR(); break; case FSTCW_ISN: emitFSTCW(); break; case FXRSTOR_ISN: emitFXRSTOR(); break; case FXSAVE_ISN: emitFXSAVE(); break; case HLT_ISN: emitHLT(); break; case IDIV_ISN: emitIDIV(); break; case IMUL_ISN: emitIMUL(); break; case IN_ISN: emitIN(); break; case INC_ISN: emitINC(); break; case INT_ISN: emitINT(); break; case IRET_ISN: emitIRET(); break; case IRETQ_ISN: emitIRETQ(); break; case JA_ISN: emitJCC(X86Assembler.JA); break; case JAE_ISN: emitJCC(X86Assembler.JAE); break; case JB_ISN: emitJCC(X86Assembler.JB); break; case JBE_ISN: emitJCC(X86Assembler.JBE); break; case JE_ISN: emitJCC(X86Assembler.JE); break; case JECXZ_ISN: emitJECXZ(); break; case JG_ISN: emitJCC(X86Assembler.JG); break; case JGE_ISN: emitJCC(X86Assembler.JGE); break; case JL_ISN: emitJCC(X86Assembler.JL); break; case JLE_ISN: emitJCC(X86Assembler.JLE); break; case JMP_ISN: emitJMP(); break; case JNA_ISN: emitJCC(X86Assembler.JNA); break; case JNE_ISN: emitJCC(X86Assembler.JNE); break; case JNZ_ISN: emitJCC(X86Assembler.JNZ); break; case JZ_ISN: emitJCC(X86Assembler.JZ); break; case LDMXCSR_ISN: emitLDMXCSR(); break; case LEA_ISN: emitLEA(); break; case LGDT_ISN: emitLGDT(); break; case LIDT_ISN: emitLIDT(); break; case LMSW_ISN: emitLMSW(); break; case LODSW_ISN: emitLODSW(); break; case LOOP_ISN: emitLOOP(); break; case LTR_ISN: emitLTR(); break; case MOV_ISN: emitMOV(); break; case MOVSB_ISN: emitMOVSB(); break; case MOVSW_ISN: emitMOVSW(); break; case MOVSD_ISN: emitMOVSD(); break; case MOVSX_ISN: emitMOVSX(); break; case MOVZX_ISN: emitMOVZX(); break; case MUL_ISN: emitMUL(); break; case NEG_ISN: emitNEG(); break; case NOP_ISN: emitNOP(); break; case NOT_ISN: emitNOT(); break; case OR_ISN: emitOR(); break; case OUT_ISN: emitOUT(); break; case POP_ISN: emitPOP(); break; case POPA_ISN: emitPOPA(); break; case POPF_ISN: emitPOPF(); break; case PUSH_ISN: emitPUSH(); break; case PUSHA_ISN: emitPUSHA(); break; case PUSHF_ISN: emitPUSHF(); break; case RDMSR_ISN: emitRDMSR(); break; case RDTSC_ISN: emitRDTSC(); break; case RET_ISN: emitRET(); break; case SBB_ISN: emitSBB(); break; case SETE_ISN: emitSETE(); break; case SAHF_ISN: emitSAHF(); break; case SAL_ISN: emitSAL(); break; case SAR_ISN: emitSAR(); break; case SHL_ISN: emitSHL(); break; case SETA_ISN: emitSETA(); break; case SETAE_ISN: emitSETAE(); break; case SETB_ISN: emitSETB(); break; case SETBE_ISN: emitSETBE(); break; case SETNE_ISN: emitSETNE(); break; case SHLD_ISN: emitSHLD(); break; case SHR_ISN: emitSHR(); break; case SHRD_ISN: emitSHRD(); break; case STD_ISN: emitSTD(); break; case STI_ISN: emitSTI(); break; case STMXCSR_ISN: emitSTMXCSR(); break; case STOSB_ISN: emitSTOSB(); break; case STOSD_ISN: emitSTOSD(); break; case STOSQ_ISN: emitSTOSQ(); break; case STOSW_ISN: emitSTOSW(); break; case SUB_ISN: emitSUB(); break; case TEST_ISN: emitTEST(); break; case WRMSR_ISN: emitWRMSR(); break; case XCHG_ISN: emitXCHG(); break; case XOR_ISN: emitXOR(); break; default: throw new Error("Invalid instruction binding " + key + " for " + mnemonic); } return true; } private void emitADC() { int addr = getAddressingMode(2); switch (addr) { case RR_ADDR: stream.writeADC(getReg(0), getReg(1)); break; case RC_ADDR: stream.writeADC(getReg(0), getInt(1)); break; case RE_ADDR: Address ind = getAddress(1); stream.writeADC(getReg(0), getRegister(ind.getImg()), ind.disp); break; case ER_ADDR: ind = getAddress(0); stream.writeADC(getRegister(ind.getImg()), ind.disp, getReg(1)); break; case EC_ADDR: ind = getAddress(0); stream.writeADC(operandSize, getRegister(ind.getImg()), ind.disp, getInt(1)); break; default: reportAddressingError(ADC_ISN, addr); } } private void emitADD() { int addr = getAddressingMode(2); switch (addr) { case RR_ADDR: stream.writeADD(getReg(0), getReg(1)); break; case RC_ADDR: stream.writeADD(getReg(0), getInt(1)); break; case RE_ADDR: Address ind = getAddress(1); stream.writeADD(getReg(0), getRegister(ind.getImg()), ind.disp); break; case RA_ADDR: ind = getAddress(1); stream.writeADD_MEM(getReg(0), ind.disp); break; case ER_ADDR: ind = getAddress(0); stream.writeADD(getRegister(ind.getImg()), ind.disp, getReg(1)); break; case EC_ADDR: ind = getAddress(0); stream.writeADD(operandSize, getRegister(ind.getImg()), ind.disp, getInt(1)); break; case AC_ADDR: stream.writeADD(operandSize, getAddress(0).disp, getInt(1)); break; case GC_ADDR: ind = getAddress(0); stream.writeADD(operandSize, (SR) X86Register.getRegister(ind.getImg()), ind.disp, getInt(1)); break; default: reportAddressingError(ADD_ISN, addr); } } private void emitALIGN() { Object o1 = operands.get(0); if (o1 instanceof Integer) { stream.align((Integer) o1); } else { throw new IllegalArgumentException("Unknown operand: " + o1); } } private void emitAND() { int addr = getAddressingMode(2); switch (addr) { case RR_ADDR: stream.writeAND(getReg(0), getReg(1)); break; case RC_ADDR: stream.writeAND(getReg(0), getInt(1)); break; case RE_ADDR: Address ind = getAddress(1); stream.writeAND(getReg(0), getRegister(ind.getImg()), ind.disp); break; case ER_ADDR: ind = getAddress(0); stream.writeAND(getRegister(ind.getImg()), ind.disp, getReg(1)); break; case EC_ADDR: ind = getAddress(0); stream.writeAND(operandSize, getRegister(ind.getImg()), ind.disp, getInt(1)); break; case AC_ADDR: stream.writeAND(operandSize, getAddress(0).disp, getInt(1)); break; case GC_ADDR: ind = getAddress(0); stream.writeAND(operandSize, (SR) X86Register.getRegister(ind.getImg()), ind.disp, getInt(1)); break; default: reportAddressingError(AND_ISN, addr); } } private void emitBTS() { int addr = getAddressingMode(2); switch (addr) { case RC_ADDR: stream.writeBTS(getReg(0), getInt(1)); break; default: reportAddressingError(BTS_ISN, addr); } } private void emitCALL() { Object o1 = operands.get(0); if (o1 instanceof Register) { stream.writeCALL(getRegister(((Register) o1).name)); } else if (o1 instanceof Identifier) { String id = ((Identifier) o1).name; Label lab = labels.get(id); lab = (lab == null) ? new Label(id) : lab; stream.writeCALL(lab); } else if (o1 instanceof Address) { Address ind = (Address) o1; if (ind.reg != null && ind.sreg != null) { throw new IllegalArgumentException("Scaled is not supported for call "); } else if (ind.reg != null) { if ("far".equals(this.instruction.getJumpType())) { stream.writeCALL_FAR(getRegister(ind.getImg()), ind.disp); } else { stream.writeCALL(getRegister(ind.getImg()), ind.disp); } } else if (ind.sreg != null) { stream.writeCALL(getRegister(ind.sreg), ind.scale, ind.disp); } else { throw new IllegalArgumentException("Absolute is not supported for call "); } } else { throw new IllegalArgumentException("Unknown operand: " + o1); } } private void emitCDQ() { stream.writeCDQ(operandSize); } private void emitCLD() { stream.writeCLD(); } private void emitCLI() { stream.writeCLI(); } private void emitCLTS() { stream.writeCLTS(); } private void emitCMP() { int addr = getAddressingMode(2); switch (addr) { case RR_ADDR: stream.writeCMP(getReg(0), getReg(1)); break; case RC_ADDR: stream.writeCMP_Const(getReg(0), getInt(1)); break; case RE_ADDR: Address ind = getAddress(1); stream.writeCMP(getReg(0), getRegister(ind.getImg()), ind.disp); break; case RA_ADDR: ind = getAddress(1); stream.writeCMP_MEM(getReg(0), ind.disp); break; case RG_ADDR: ind = getAddress(1); stream.writeCMP(getReg(0), (SR) X86Register.getRegister(ind.getImg()), ind.disp); break; case ER_ADDR: ind = getAddress(0); stream.writeCMP(getRegister(ind.getImg()), ind.disp, getReg(1)); break; case EC_ADDR: ind = getAddress(0); stream.writeCMP_Const(operandSize, getRegister(ind.getImg()), ind.disp, getInt(1)); break; case AC_ADDR: ind = getAddress(0); stream.writeCMP_MEM(operandSize, ind.disp, getInt(1)); break; case GC_ADDR: ind = getAddress(0); stream.writeCMP_Const(operandSize, (SR) X86Register.getRegister(ind.getImg()), ind.disp, getInt(1)); break; default: reportAddressingError(CMP_ISN, addr); } } private void emitCMPXCHG() { int addr = getAddressingMode(2); switch (addr) { case ER_ADDR: Address ind = getAddress(0); //prefix is already written stream.writeCMPXCHG_EAX(getRegister(ind.getImg()), ind.disp, getReg(1), false); break; default: reportAddressingError(CMPXCHG_ISN, addr); } } private void emitCPUID() { stream.writeCPUID(); } private void emitDEC() { int addr = getAddressingMode(1); switch (addr) { case R_ADDR: stream.writeDEC(getReg(0)); break; case E_ADDR: Address ind = getAddress(0); stream.writeDEC(operandSize, getRegister(ind.getImg()), ind.disp); break; default: reportAddressingError(DEC_ISN, addr); } } private void emitDIV() { int addr = getAddressingMode(1); switch (addr) { case R_ADDR: stream.writeDIV_EAX(getReg(0)); break; default: reportAddressingError(DIV_ISN, addr); } } private void emitFLDCW() { int addr = getAddressingMode(1); switch (addr) { case E_ADDR: Address ind = getAddress(0); stream.writeFLDCW(getRegister(ind.getImg()), ind.disp); break; default: reportAddressingError(FLDCW_ISN, addr); } } private void emitFNINIT() { stream.writeFNINIT(); } private void emitFNSAVE() { int addr = getAddressingMode(1); switch (addr) { case E_ADDR: Address ind = getAddress(0); stream.writeFNSAVE(getRegister(ind.getImg()), ind.disp); break; default: reportAddressingError(FNSAVE_ISN, addr); } } private void emitFRSTOR() { int addr = getAddressingMode(1); switch (addr) { case E_ADDR: Address ind = getAddress(0); stream.writeFRSTOR(getRegister(ind.getImg()), ind.disp); break; default: reportAddressingError(FRSTOR_ISN, addr); } } private void emitFSTCW() { int addr = getAddressingMode(1); switch (addr) { case E_ADDR: Address ind = getAddress(0); stream.writeFSTCW(getRegister(ind.getImg()), ind.disp); break; default: reportAddressingError(FSTCW_ISN, addr); } } private void emitFXRSTOR() { int addr = getAddressingMode(1); switch (addr) { case E_ADDR: Address ind = getAddress(0); stream.writeFXRSTOR(getRegister(ind.getImg()), ind.disp); break; default: reportAddressingError(FXRSTOR_ISN, addr); } } private void emitFXSAVE() { int addr = getAddressingMode(1); switch (addr) { case E_ADDR: Address ind = getAddress(0); stream.writeFXSAVE(getRegister(ind.getImg()), ind.disp); break; default: reportAddressingError(FXSAVE_ISN, addr); } } private void emitHLT() { stream.writeHLT(); } private void emitIDIV() { int addr = getAddressingMode(1); switch (addr) { case R_ADDR: GPR reg = getReg(0); stream.writeIDIV_EAX(reg); break; case E_ADDR: Address ind = getAddress(0); stream.writeIDIV_EAX(operandSize, getRegister(ind.getImg()), ind.disp); break; default: reportAddressingError(IDIV_ISN, addr); } } private void emitIMUL() { int addr = getAddressingMode(3); switch (addr) { case R_ADDR: GPR reg = getReg(0); stream.writeIMUL_EAX(reg); break; case RR_ADDR: GPR reg1 = getReg(0); GPR reg2 = getReg(1); stream.writeIMUL(reg1, reg2); break; case RE_ADDR: reg = getReg(0); Address ind = getAddress(1); stream.writeIMUL(reg, getRegister(ind.getImg()), ind.disp); break; case RRC_ADDR: reg1 = getReg(0); reg2 = getReg(1); int imm = getInt(2); stream.writeIMUL_3(reg1, reg2, imm); break; case REC_ADDR: reg = getReg(0); ind = getAddress(0); imm = getInt(2); stream.writeIMUL_3(reg, getRegister(ind.getImg()), ind.disp, imm); break; default: reportAddressingError(IMUL_ISN, addr); } } private void emitIN() { int addr = getAddressingMode(2); switch (addr) { case RR_ADDR: GPR reg2 = getReg(1); if (reg2 != X86Register.DX) { throw new IllegalArgumentException("Invalid second operand for IN: " + reg2); } GPR reg1 = getReg(0); if (reg1 == X86Register.AL) { stream.writeIN(X86Constants.BITS8); } else if (reg1 == X86Register.AX) { stream.writeIN(X86Constants.BITS16); } else if (reg1 == X86Register.EAX) { stream.writeIN(X86Constants.BITS32); } else { throw new IllegalArgumentException("Invalid first operand for IN: " + reg1); } break; case RC_ADDR: reg1 = getReg(0); if (reg1 == X86Register.AL) { stream.writeIN(X86Constants.BITS8, getInt(1)); } else if (reg1 == X86Register.AX) { stream.writeIN(X86Constants.BITS16, getInt(1)); } else if (reg1 == X86Register.EAX) { stream.writeIN(X86Constants.BITS32, getInt(1)); } else { throw new IllegalArgumentException("Invalid first operand for IN: " + reg1); } break; default: reportAddressingError(IN_ISN, addr); } } private void emitINC() { int addr = getAddressingMode(1); switch (addr) { case R_ADDR: stream.writeINC(getReg(0)); break; case E_ADDR: Address ind = getAddress(0); stream.writeINC(operandSize, getRegister(ind.getImg()), ind.disp); break; case A_ADDR: stream.writeINC(operandSize, getAddress(0).disp); break; case S_ADDR: ind = getAddress(0); stream.writeINC(operandSize, getRegister(ind.getImg()), getRegister(ind.sreg), ind.scale, ind.disp); break; case G_ADDR: ind = getAddress(0); stream.writeINC(operandSize, (SR) X86Register.getRegister(ind.getImg()), ind.disp); break; default: reportAddressingError(INC_ISN, addr); } } private void emitINT() { Object o1 = operands.get(0); Integer val; if (o1 instanceof Identifier) { String id = ((Identifier) o1).name; val = constants.get(id); } else if (o1 instanceof Integer) { val = (Integer) o1; } else { throw new IllegalArgumentException("Unknown operand: " + o1); } if (val != null) { stream.writeINT(val); } else { throw new IllegalArgumentException("Missing operand for INT"); } } private void emitIRET() { stream.writeIRET(); } private void emitIRETQ() { stream.writeIRETQ(); } private void emitJCC(int jumpCode) { Object o1 = operands.get(0); if (o1 instanceof Identifier) { String id = ((Identifier) o1).name; Label lab = labels.get(id); lab = (lab == null) ? new Label(id) : lab; stream.writeJCC(lab, jumpCode); } else { throw new IllegalArgumentException("Unknown operand: " + o1); } } private void emitJECXZ() { Object o1 = operands.get(0); if (o1 instanceof Identifier) { String id = ((Identifier) o1).name; Label lab = labels.get(id); lab = (lab == null) ? new Label(id) : lab; stream.writeJECXZ(lab); } else { throw new IllegalArgumentException("Unknown operand: " + o1); } } private void emitJMP() { Object o1 = operands.get(0); if (o1 instanceof Register) { stream.writeJMP(getRegister(((Register) o1).name)); } else if (o1 instanceof Identifier) { String id = ((Identifier) o1).name; Label lab = labels.get(id); lab = (lab == null) ? new Label(id) : lab; stream.writeJMP(lab); } else if (o1 instanceof Address) { Address addr = (Address) o1; if (addr.reg != null) { stream.writeJMP(getRegister(addr.reg), addr.disp); } else { stream.writeJMP(operandSize, addr.scale, addr.disp); } } else { throw new IllegalArgumentException("Unknown operand: " + o1); } } private void emitLDMXCSR() { int addr = getAddressingMode(1); switch (addr) { case E_ADDR: Address ind = getAddress(0); stream.writeLDMXCSR(getRegister(ind.getImg()), ind.disp); break; default: reportAddressingError(LDMXCSR_ISN, addr); } } private void emitLEA() { int addr = getAddressingMode(2); switch (addr) { case RE_ADDR: Address ind = getAddress(1); stream.writeLEA(getReg(0), getRegister(ind.getImg()), ind.disp); break; case RS_ADDR: ind = getAddress(1); stream.writeLEA(getReg(0), getRegister(ind.getImg()), getRegister(ind.sreg), ind.scale, ind.disp); break; case RZ_ADDR: ind = getAddress(1); stream.writeLEA(getReg(0), getRegister(ind.sreg), ind.scale, ind.disp); break; default: reportAddressingError(LEA_ISN, addr); } } private void emitLGDT() { int addr = getAddressingMode(1); switch (addr) { case A_ADDR: stream.writeLGDT(getAddress(0).disp); break; default: reportAddressingError(LGDT_ISN, addr); } } private void emitLIDT() { int addr = getAddressingMode(1); switch (addr) { case A_ADDR: stream.writeLIDT(getAddress(0).disp); break; default: reportAddressingError(LIDT_ISN, addr); } } private void emitLMSW() { int addr = getAddressingMode(1); switch (addr) { case R_ADDR: stream.writeLMSW(getReg(0)); break; default: reportAddressingError(LMSW_ISN, addr); } } private void emitLODSW() { stream.writeLODSW(); } private void emitLOOP() { Object o1 = operands.get(0); if (o1 instanceof Identifier) { String id = ((Identifier) o1).name; Label lab = labels.get(id); lab = (lab == null) ? new Label(id) : lab; try { stream.writeLOOP(lab); } catch (UnresolvedObjectRefException x) { x.printStackTrace(); } } else { throw new IllegalArgumentException("Unknown operand: " + o1); } } private void emitLTR() { int addr = getAddressingMode(1); switch (addr) { case R_ADDR: stream.writeLTR(getReg(0)); break; default: reportAddressingError(LTR_ISN, addr); } } private void emitMOV() { if (operands.size() == 2 && operands.get(0) instanceof Register && operands.get(1) instanceof Identifier) { stream.writeMOV_Const(getRegister(((Register) operands.get(0)).name), new Label(((Identifier) operands.get(1)).name)); return; } int addr = getAddressingMode(2); switch (addr) { case RR_ADDR: X86Register r1 = X86Register.getRegister(((Register) args[0]).name); X86Register r2 = X86Register.getRegister(((Register) args[1]).name); if (r1 instanceof GPR && r2 instanceof GPR) { int s1 = r1.getSize(); int s2 = r2.getSize(); if (s1 != s2) { throw new IllegalArgumentException("Incompatible register pair: " + r1 + "," + r2); } stream.writeMOV(s1, (GPR) r1, (GPR) r2); } else if (r1 instanceof CRX && r2 instanceof GPR) { stream.writeMOV((CRX) r1, (GPR) r2); } else if (r1 instanceof GPR && r2 instanceof CRX) { stream.writeMOV((GPR) r1, (CRX) r2); } else if (r1 instanceof SR && r2 instanceof GPR) { stream.writeMOV((SR) r1, (GPR) r2); } else if (r1 instanceof GPR && r2 instanceof SR) { stream.writeMOV((GPR) r1, (SR) r2); } else { throw new IllegalArgumentException("Invalid register usage: mov " + r1 + "," + r2); } break; case RC_ADDR: stream.writeMOV_Const(getReg(0), getInt(1)); break; case RE_ADDR: GPR r = getReg(0); Address ind = getAddress(1); stream.writeMOV(r.getSize(), r, getRegister(ind.getImg()), ind.disp); break; case RA_ADDR: stream.writeMOV(getReg(0), getAddress(1).disp); break; case RG_ADDR: ind = getAddress(1); stream.writeMOV(getReg(0), (SR) X86Register.getRegister(ind.getImg()), ind.disp); break; case RS_ADDR: ind = getAddress(1); stream.writeMOV(operandSize, getReg(0), getRegister(ind.getImg()), getRegister(ind.sreg), ind.scale, ind.disp); break; case ER_ADDR: ind = getAddress(0); int oSize = operandSize; if (oSize > getReg(1).getSize()) { oSize = getReg(1).getSize(); } stream.writeMOV(oSize, getRegister(ind.getImg()), ind.disp, getReg(1)); break; case EC_ADDR: ind = getAddress(0); stream.writeMOV_Const(operandSize, getRegister(ind.getImg()), ind.disp, getInt(1)); break; case AR_ADDR: stream.writeMOV(getAddress(0).disp, getReg(1)); break; case AC_ADDR: stream.writeMOV_Const(operandSize, getAddress(0).disp, getInt(1)); break; case SR_ADDR: ind = getAddress(0); stream.writeMOV(operandSize, getRegister(ind.getImg()), getRegister(ind.sreg), ind.scale, ind.disp, getReg(1)); break; case GR_ADDR: ind = getAddress(0); stream.writeMOV((SR) X86Register.getRegister(ind.getImg()), ind.disp, getReg(1)); break; case GC_ADDR: ind = getAddress(0); stream.writeMOV_Const(operandSize, (SR) X86Register.getRegister(ind.getImg()), ind.disp, getInt(1)); break; default: reportAddressingError(MOV_ISN, addr); } } private void emitMOVSB() { stream.writeMOVSB(); } private void emitMOVSW() { stream.writeMOVSW(); } private void emitMOVSD() { stream.writeMOVSD(); } private void emitMOVSX() { int addr = getAddressingMode(2); switch (addr) { case RR_ADDR: GPR reg2 = getReg(1); stream.writeMOVSX(getReg(0), reg2, operandSize); break; case RE_ADDR: Address ind = getAddress(1); stream.writeMOVSX(getReg(0), getRegister(ind.getImg()), ind.disp, operandSize); break; default: reportAddressingError(MOVSX_ISN, addr); } } private void emitMOVZX() { int addr = getAddressingMode(2); switch (addr) { case RR_ADDR: GPR reg2 = getReg(1); int os = operandSize == X86Constants.BITS32 ? reg2.getSize() : operandSize; stream.writeMOVZX(getReg(0), reg2, os); break; case RE_ADDR: Address ind = getAddress(1); stream.writeMOVZX(getReg(0), getRegister(ind.getImg()), ind.disp, operandSize); break; default: reportAddressingError(MOVZX_ISN, addr); } } private void emitMUL() { int addr = getAddressingMode(1); switch (addr) { case R_ADDR: stream.writeMUL_EAX(getReg(0)); break; default: reportAddressingError(MUL_ISN, addr); } } private void emitNEG() { int addr = getAddressingMode(1); switch (addr) { case R_ADDR: stream.writeNEG(getReg(0)); break; case E_ADDR: Address ind = getAddress(0); stream.writeNEG(operandSize, getRegister(ind.getImg()), ind.disp); break; default: reportAddressingError(NEG_ISN, addr); } } private void emitNOP() { stream.writeNOP(); } private void emitNOT() { int addr = getAddressingMode(1); switch (addr) { case R_ADDR: stream.writeNOT(getReg(0)); break; case E_ADDR: Address ind = getAddress(0); stream.writeNOT(operandSize, getRegister(ind.getImg()), ind.disp); break; default: reportAddressingError(NOT_ISN, addr); } } private void emitOR() { int addr = getAddressingMode(2); switch (addr) { case RR_ADDR: stream.writeOR(getReg(0), getReg(1)); break; case RC_ADDR: stream.writeOR(getReg(0), getInt(1)); break; case RE_ADDR: Address ind = getAddress(1); stream.writeOR(getReg(0), getRegister(ind.getImg()), ind.disp); break; case ER_ADDR: ind = getAddress(0); stream.writeOR(getRegister(ind.getImg()), ind.disp, getReg(1)); break; case EC_ADDR: ind = getAddress(0); stream.writeOR(operandSize, getRegister(ind.getImg()), ind.disp, getInt(1)); break; case AC_ADDR: stream.writeOR(operandSize, getAddress(0).disp, getInt(1)); break; case GC_ADDR: ind = getAddress(0); stream.writeOR(operandSize, (SR) X86Register.getRegister(ind.getImg()), ind.disp, getInt(1)); break; default: reportAddressingError(OR_ISN, addr); } } private void emitOUT() { int addr = getAddressingMode(2); switch (addr) { case RR_ADDR: GPR reg1 = getReg(0); if (reg1 != X86Register.DX) { throw new IllegalArgumentException("Invalid second operand for OUT: " + reg1 + ", must be " + X86Register.DX); } GPR reg2 = getReg(1); if (reg2 == X86Register.AL) { stream.writeOUT(X86Constants.BITS8); } else if (reg2 == X86Register.AX) { stream.writeOUT(X86Constants.BITS16); } else if (reg2 == X86Register.EAX) { stream.writeOUT(X86Constants.BITS32); } else { throw new IllegalArgumentException("Invalid first operand for OUT: " + reg2); } break; case CR_ADDR: reg2 = getReg(1); if (reg2 == X86Register.AL) { stream.writeOUT(X86Constants.BITS8, getInt(0)); } else if (reg2 == X86Register.AX) { stream.writeOUT(X86Constants.BITS16, getInt(0)); } else if (reg2 == X86Register.EAX) { stream.writeOUT(X86Constants.BITS32, getInt(0)); } else { throw new IllegalArgumentException("Invalid first operand for OUT: " + reg2); } break; default: reportAddressingError(OUT_ISN, addr); } } private void emitPOP() { int addr = getAddressingMode(1); switch (addr) { case R_ADDR: X86Register r1 = X86Register.getRegister(((Register) args[0]).name); if (r1 instanceof GPR) { stream.writePOP((GPR) r1); } else if (r1 instanceof SR) { stream.writePOP((SR) r1); } else { throw new IllegalArgumentException("Invalid register usage: pop " + r1); } break; case E_ADDR: Address ind = getAddress(0); stream.writePOP(getRegister(ind.getImg()), ind.disp); break; default: reportAddressingError(POP_ISN, addr); } } private void emitPOPA() { stream.writePOPA(); } private void emitPOPF() { stream.writePOPF(); } private void emitPUSH() { if (operands.size() == 1 && operands.get(0) instanceof Identifier) { stream.writePUSH_Const(new Label(((Identifier) operands.get(0)).name)); return; } int addr = getAddressingMode(1); switch (addr) { case C_ADDR: stream.writePUSH(getInt(0)); break; case R_ADDR: X86Register r1 = X86Register.getRegister(((Register) args[0]).name); if (r1 instanceof GPR) { stream.writePUSH((GPR) r1); } else if (r1 instanceof SR) { stream.writePUSH((SR) r1); } else { throw new IllegalArgumentException("Invalid register usage: push " + r1); } break; case E_ADDR: Address ind = getAddress(0); stream.writePUSH(getRegister(ind.getImg()), ind.disp); break; case G_ADDR: ind = getAddress(0); r1 = X86Register.getRegister(ind.getImg()); stream.writePUSH((SR) r1, ind.disp); break; default: reportAddressingError(PUSH_ISN, addr); } } private void emitPUSHA() { stream.writePUSHA(); } private void emitPUSHF() { stream.writePUSHF(); } private void emitRDMSR() { stream.writeRDMSR(); } private void emitRDTSC() { stream.writeRDTSC(); } private void emitRET() { int addr = getAddressingMode(1); switch (addr) { case N_ADDR: stream.writeRET(); break; case C_ADDR: stream.writeRET(getInt(0)); break; default: reportAddressingError(RET_ISN, addr); } } private void emitSBB() { int addr = getAddressingMode(2); switch (addr) { case RR_ADDR: stream.writeSBB(getReg(0), getReg(1)); break; case RE_ADDR: Address ind = getAddress(1); stream.writeSBB(getReg(0), getRegister(ind.getImg()), ind.disp); break; case RC_ADDR: stream.writeSBB(getReg(0), getInt(1)); break; default: reportAddressingError(SBB_ISN, addr); } } private void emitSETE() { int addr = getAddressingMode(1); switch (addr) { case R_ADDR: stream.writeSETCC(getReg(0), X86Constants.JE); break; default: reportAddressingError(SETE_ISN, addr); } } private void emitSAHF() { stream.writeSAHF(); } private void emitSAL() { int addr = getAddressingMode(2); switch (addr) { case RR_ADDR: GPR reg = getReg(1); if (reg.equals(X86Register.CL)) { stream.writeSAL_CL(getReg(0)); } else { throw new IllegalArgumentException("Invalid second operand for SAL: " + reg + ", must be " + X86Register.CL); } break; case RC_ADDR: stream.writeSAL(getReg(0), getInt(1)); break; case EC_ADDR: Address ind = getAddress(0); stream.writeSAL(operandSize, getRegister(ind.getImg()), ind.disp, getInt(1)); break; default: reportAddressingError(SAL_ISN, addr); } } private void emitSAR() { int addr = getAddressingMode(2); switch (addr) { case RR_ADDR: GPR reg = getReg(1); if (reg.equals(X86Register.CL)) { stream.writeSAR_CL(getReg(0)); } else { throw new IllegalArgumentException("Invalid second operand for SAR: " + reg + ", must be " + X86Register.CL); } break; case RC_ADDR: stream.writeSAR(getReg(0), getInt(1)); break; case EC_ADDR: Address ind = getAddress(0); stream.writeSAR(operandSize, getRegister(ind.getImg()), ind.disp, getInt(1)); break; default: reportAddressingError(SAR_ISN, addr); } } private void emitSHL() { int addr = getAddressingMode(2); switch (addr) { case RR_ADDR: GPR reg = getReg(1); if (reg.equals(X86Register.CL)) { stream.writeSHL_CL(getReg(0)); } else { throw new IllegalArgumentException("Invalid second operand for SHL: " + reg + ", must be " + X86Register.CL); } break; case RC_ADDR: stream.writeSHL(getReg(0), getInt(1)); break; case EC_ADDR: Address ind = getAddress(0); stream.writeSHL(operandSize, getRegister(ind.getImg()), ind.disp, getInt(1)); break; default: reportAddressingError(SHL_ISN, addr); } } private void emitSETA() { int addr = getAddressingMode(1); switch (addr) { case R_ADDR: stream.writeSETCC(getReg(0), X86Constants.JA); break; default: reportAddressingError(SETA_ISN, addr); } } private void emitSETAE() { int addr = getAddressingMode(1); switch (addr) { case R_ADDR: stream.writeSETCC(getReg(0), X86Constants.JAE); break; default: reportAddressingError(SETAE_ISN, addr); } } private void emitSETB() { int addr = getAddressingMode(1); switch (addr) { case R_ADDR: stream.writeSETCC(getReg(0), X86Constants.JB); break; default: reportAddressingError(SETB_ISN, addr); } } private void emitSETBE() { int addr = getAddressingMode(1); switch (addr) { case R_ADDR: stream.writeSETCC(getReg(0), X86Constants.JBE); break; default: reportAddressingError(SETBE_ISN, addr); } } private void emitSETNE() { int addr = getAddressingMode(1); switch (addr) { case R_ADDR: stream.writeSETCC(getReg(0), X86Constants.JNE); break; default: reportAddressingError(SETNE_ISN, addr); } } private void emitSHLD() { int addr = getAddressingMode(2); switch (addr) { case RR_ADDR: stream.writeSHLD_CL(getReg(0), getReg(1)); break; default: reportAddressingError(SHLD_ISN, addr); } } private void emitSHR() { int addr = getAddressingMode(2); switch (addr) { case RR_ADDR: GPR reg = getReg(1); if (reg.equals(X86Register.CL)) { stream.writeSHR_CL(getReg(0)); } else { throw new IllegalArgumentException("Invalid second operand for SHR: " + reg + ", must be " + X86Register.CL); } break; case RC_ADDR: stream.writeSHR(getReg(0), getInt(1)); break; case EC_ADDR: Address ind = getAddress(0); stream.writeSHR(operandSize, getRegister(ind.getImg()), ind.disp, getInt(1)); break; default: reportAddressingError(SHR_ISN, addr); } } private void emitSHRD() { int addr = getAddressingMode(3); switch (addr) { case RRR_ADDR: GPR reg = getReg(2); if (reg.equals(X86Register.CL)) { stream.writeSHRD_CL(getReg(0), getReg(1)); } else { throw new IllegalArgumentException("Invalid second operand for SHRD: " + reg + ", must be " + X86Register.CL); } break; default: reportAddressingError(SHRD_ISN, addr); } } private void emitSTD() { stream.writeSTD(); } private void emitSTI() { stream.writeSTI(); } private void emitSTMXCSR() { int addr = getAddressingMode(1); switch (addr) { case E_ADDR: Address ind = getAddress(0); stream.writeSTMXCSR(getRegister(ind.getImg()), ind.disp); break; default: reportAddressingError(STMXCSR_ISN, addr); } } private void emitSTOSB() { stream.writeSTOSB(); } private void emitSTOSD() { stream.writeSTOSD(); } private void emitSTOSQ() { stream.writeSTOSQ(); } private void emitSTOSW() { stream.writeSTOSW(); } private void emitSUB() { int addr = getAddressingMode(2); switch (addr) { case RR_ADDR: stream.writeSUB(getReg(0), getReg(1)); break; case RC_ADDR: stream.writeSUB(getReg(0), getInt(1)); break; case RE_ADDR: Address ind = getAddress(1); stream.writeSUB(getReg(0), getRegister(ind.getImg()), ind.disp); break; case ER_ADDR: ind = getAddress(0); stream.writeSUB(getRegister(ind.getImg()), ind.disp, getReg(1)); break; case EC_ADDR: ind = getAddress(0); stream.writeSUB(operandSize, getRegister(ind.getImg()), ind.disp, getInt(1)); break; case AR_ADDR: stream.writeSUB(getAddress(0).disp, getReg(1)); break; default: reportAddressingError(SUB_ISN, addr); } } private void emitTEST() { int addr = getAddressingMode(2); switch (addr) { case RR_ADDR: stream.writeTEST(getReg(0), getReg(1)); break; case RC_ADDR: stream.writeTEST(getReg(0), getInt(1)); break; case EC_ADDR: Address ind = getAddress(0); stream.writeTEST(operandSize, getRegister(ind.getImg()), ind.disp, getInt(1)); break; case AC_ADDR: stream.writeTEST(operandSize, getAddress(0).disp, getInt(1)); break; case GC_ADDR: ind = getAddress(0); stream.writeTEST(operandSize, (SR) X86Register.getRegister(ind.getImg()), ind.disp, getInt(1)); break; default: reportAddressingError(TEST_ISN, addr); } } private void emitWRMSR() { stream.writeWRMSR(); } private void emitXCHG() { int addr = getAddressingMode(2); switch (addr) { case RR_ADDR: stream.writeXCHG(getReg(0), getReg(1)); break; case RE_ADDR: Address ind = getAddress(1); stream.writeXCHG(getRegister(ind.getImg()), ind.disp, getReg(0)); break; case RA_ADDR: stream.writeXCHG(getAddress(1).disp, getReg(0)); break; case RG_ADDR: ind = getAddress(1); stream.writeXCHG((SR) X86Register.getRegister(ind.getImg()), ind.disp, getReg(0)); break; case ER_ADDR: ind = getAddress(0); stream.writeXCHG(getRegister(ind.getImg()), ind.disp, getReg(1)); break; case AR_ADDR: stream.writeXCHG(getAddress(0).disp, getReg(1)); break; case GR_ADDR: ind = getAddress(0); stream.writeXCHG((SR) X86Register.getRegister(ind.getImg()), ind.disp, getReg(1)); break; default: reportAddressingError(XCHG_ISN, addr); } } private void emitXOR() { int addr = getAddressingMode(2); switch (addr) { case RR_ADDR: stream.writeXOR(getReg(0), getReg(1)); break; case RC_ADDR: stream.writeXOR(getReg(0), getInt(1)); break; case RE_ADDR: Address ind = getAddress(1); stream.writeXOR(getReg(0), getRegister(ind.getImg()), ind.disp); break; case ER_ADDR: ind = getAddress(0); stream.writeXOR(getRegister(ind.getImg()), ind.disp, getReg(1)); break; case EC_ADDR: ind = getAddress(0); stream.writeXOR(operandSize, getRegister(ind.getImg()), ind.disp, getInt(1)); break; default: reportAddressingError(XOR_ISN, addr); } } }