📄 intel86.j4
字号:
rv [0] = (byte) b0; return rv; } /** Return a two-element byte array with parameters as elements. * @param b0 value to store in array * @param b1 value to store in array * @returns byte[] array of b0 and b1 */ private byte [] makeByteArray (int b0, int b1) { byte rv [] = new byte [2]; rv [0] = (byte) b0; rv [1] = (byte) b1; return rv; } /** Convert an Immediate operand into a byte array of its value, stored * little-endian, and to the size required. * @param im immedate operand * @returns byte[] array of encoded immediate */ private byte [] makeByteArray (Immediate im) { byte rv []; int rvs; int immv; rvs = 0; immv = im.getValue (); switch (im.getImmSize ()) { case 1: rv = new byte [1]; rv [rvs++] = (byte) immv; break; case 2: /* Store little-endian */ rv = new byte [2]; rv [rvs++] = (byte) immv; rv [rvs++] = (byte) ((immv >> 8) & 0xFF); break; case 4: /* Store little-endian */ rv = new byte [4]; rv [rvs++] = (byte) ((immv >> 0) & 0xFF); rv [rvs++] = (byte) ((immv >> 8) & 0xFF); rv [rvs++] = (byte) ((immv >> 16) & 0xFF); rv [rvs++] = (byte) ((immv >> 24) & 0xFF); break; default: throw new InternalError ("Intel86/makeByteArray: Invalid immediate rep size: " + im); } return rv; } /** Add a one-byte instruction to the code block. * @param b0 byte value of instruction * @returns byte[] encoded instruction bytes */ private byte [] encode (int b0) { byte rv [] = new byte [1]; rv [0] = (byte) b0; return addByteArray (rv); } /** Add a two-byte instruction to the code block. * @param b0 byte value of instruction * @param b1 byte value of instruction * @returns byte[] encoded instruction bytes */ private byte [] encode (int b0, int b1) { byte rv [] = new byte [2]; rv [0] = (byte) b0; rv [1] = (byte) b1; return addByteArray (rv); } /** Verify that an operand exists, and return its type. * @param op Arbitrary operand: Immediate, Register, MemoryRef, .... * @returns int operand type code */ private int checkOperand (Object op) { int ot; ot = OpType (op); if (OT_absent == ot) { throw new InternalError ("x86: missing required operand"); } return ot; } /** The S flag is set when the instruction has a 8-bit immediate whose * value is to be sign-extended into a 32-bit operand. It lives in * bit 1 of the opcode byte. */ private static final int SFlag = 0x02; /** Determine for a given object (which better be an Immediate), whether * the S flag should be set. * @param ob operand to use for check * @returns int value to be ORd onto opcode to set S flag */ private int valSFlag (Object ob) { Immediate iOp; iOp = (Immediate) ob; if ((! iOp.getSignExtendFlagVal ()) && (1 == iOp.getImmSize ())) { /* What I mean by this is, it turns out that a non-zero * S-flag usually is the indication that there is an 8-bit * immediate, so if we set it to 0, the processor will look * for a 32-bit immediate. This is borne out by the fact * that gcc/gdb won't recognize instructions with the S-flag * set and the W-flag clear. */ throw new InternalError ("Intel86: Checking for S-flag on unsigned 8-bit immediate: this is wrong."); } return ((Immediate)ob).getSignExtend () ? SFlag : 0; } /** The W flag is set when the instruction is to use the 8-bit * registers, or a one-byte memory reference, rather than larger * ones. It lives in bit 0 of the opcode byte. */ private static final int WFlag = 0x01; /** Determine for a given object (which better be a register or * memory reference) whether the S flag should be set. * @param ob operand to use for check * @returns int value to be ORd onto opcode to set W flag */ private int valWFlag (Object ob) { int ot = OpType (ob); int fv = WFlag; if (OT_mem == ot) { if (1 == ((MemoryRef)ob).getRefSize ()) { fv = 0; } } else if (OT_reg == ot) { if (((Register)ob).is8BitReg ()) { fv = 0; } } else { throw new InternalError ("Intel86: Unexpected operand for wflag set: " + ob); } return fv; } /** Binary version of valWFlag, when there are two operands and we * don't know which of them has the necessary size info. We have * to have either a register or a memory ref or both, and we can't * have two memory refs. * @param ob1 operand to use for check * @param ob2 operand to use for check * @returns int value to be ORd onto opcode to set W flag */ private int valWFlag (Object ob1, Object ob2) { if (OT_reg == OpType (ob1)) { return ((Register)ob1).is8BitReg () ? 0x00 : WFlag; } return valWFlag (ob2); } /** The D flag is set when the source and destination operands are * reversed, as with memory-to-register operations. It lives in * bit 1 of the opcode byte. */ private static final int DFlag = 0x02; /** Determine, for a specific pair of source and destination operands, * whether we swapped them in the modr/m byte. * @param src source operand * @param dst destination operand * @returns int value to be ORd onto opcode to set D flag */ private int valDFlag (Object src, Object dst) { return ((OT_mem == OpType (src)) && (OT_reg == OpType (dst))) ? DFlag : 0; } /** The F flag is set for FPU-to-memory transfers when the value * to be transferred is larger than 4 bytes (specifically, when * it is eight bytes). It lives in bit 3 of the opcode byte. */ private static final int FFlag = 0x04; /** Determine for a given object (which better be a memory reference) * whether the F flag should be set. * @param ob operand to use for check * @returns int value to be ORd onto opcode to set F flag */ private int valFFlag (Object ob) { return (4 < ((MemoryRef) ob).getRefSize ()) ? FFlag : 0x00; } /** Assemble a CALL instruction */ public byte [] CALL (Object dst) { int dot = checkOperand (dst); if (OT_imm == dot) { return encode (makeByteArray (0xe8), null, makeByteArray (((Immediate)dst).setImmSize (4))); } if ((OT_reg != dot) && (OT_mem != dot)) { throw new InternalError ("Intel86: Improper operand to CALL: " + dst); } return encode (makeByteArray (0xFF), makeModRM (0x02, dst), null); } /** Assemble a near conditional jump instruction */ public byte [] Jccn (int cond, Object dst) { Immediate iOp; try { iOp = (Immediate) dst; } catch (ClassCastException e) { throw new InternalError ("Intel86: Require immediate for JMPn parameter\n"); } if (1 != iOp.getImmSize ()) { throw new InternalError ("Intel86: Immediate value out-of-range for near jump: " + iOp); } return encode (0x70 | cond, iOp.getValue ()); } /** Assemble a far-but-same-segment conditional jump instruction */ public byte [] Jcc (int cond, Object dst) { Immediate iOp; try { iOp = (Immediate) dst; } catch (ClassCastException e) { throw new InternalError ("Intel86: Require immediate for JMP parameter\n"); } return encode (makeByteArray (0x0F, 0x80 | cond), null, makeByteArray (iOp.setImmSize (4))); } /** Assemble a far-but-same-segment unconditional jump instruction */ public byte [] JMP (Object dst) { int dot = checkOperand (dst); if (OT_imm == dot) { return encode (makeByteArray (0xe9), null, makeByteArray (((Immediate)dst).setImmSize (4))); } if ((OT_reg != dot) && (OT_mem != dot)) { throw new InternalError ("Intel86: Bad type arg for register/memory-indirect jump: " + dst); } if ((OT_reg == dot) && ((Register)dst).is8BitReg ()) { throw new InternalError ("Intel86: Require 32bit reg for indirect JMP: " + dst); } return encode (makeByteArray (0xff), makeModRM (0x04, dst), null); } /** Assemble a near unconditional jump instruction */ public byte [] JMPn (Object dst) { Immediate iOp; try { iOp = (Immediate) dst; } catch (ClassCastException e) { throw new InternalError ("Intel86: Require immediate for JMPn parameter\n"); } if (1 != iOp.getImmSize ()) { throw new InternalError ("Intel86: Immediate value out-of-range for near jump: " + iOp); } return encode (0xeb, iOp.getValue ()); } /** Assemble an LEA instruction */ public byte [] LEA (Object src, Object dst) { if (! ((OT_mem == OpType (src)) && (OT_reg == OpType (dst)))) { throw new InternalError ("x86: invalid operands to LEA"); } return encode (makeByteArray (0x8d), makeModRM (src, dst), null); } /** Assemble a MOV instruction */ public byte [] MOV (Object src, Object dst) { int sot = checkOperand (src); int dot = checkOperand (dst); if (OT_imm == sot) { Immediate iOp = (Immediate) src; if (OT_reg == dot) { Register rOp = (Register) dst; if (2 == iOp.getImmSize ()) { throw new InternalError ("Intel86: Interface doesn't permit 16-bit immediate MOVs."); } iOp = iOp.setImmSize (rOp.is8BitReg () ? 1 : 4); return encode (makeByteArray (0xb0 | (valWFlag (dst) << 3) | rOp.getRegBitName ()), null, makeByteArray (iOp)); } int wFlag = valWFlag (dst); return encode (makeByteArray (0xc6 | wFlag), makeModRM (0x00, dst), makeByteArray (iOp.setImmSize ((0 == wFlag) ? 1 : 4))); } return encode (makeByteArray (0x88 | valDFlag (src, dst) | valWFlag (src, dst)), makeModRM (src, dst), null); } /** Assemble a NEG instruction */ public byte [] NEG (Object dst) { int dot = checkOperand (dst); if (OT_imm == dot) { throw new InternalError ("Intel86: Invalid operand to NEG: " + dst); } return encode (makeByteArray (0xf6 | valWFlag (dst)), makeModRM (0x03, dst), null); } /** Assemble a POP instruction */ public byte [] POP (Object dst) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -