📄 x86assembler.h
字号:
static void patchPointer(intptr_t where, intptr_t value) { reinterpret_cast<intptr_t*>(where)[-1] = value; } void* executableCopy(ExecutablePool* allocator) { void* copy = m_formatter.executableCopy(allocator); ASSERT(copy); return copy; }private: class X86InstructionFormatter { static const int maxInstructionSize = 16; public: // Legacy prefix bytes: // // These are emmitted prior to the instruction. void prefix(OneByteOpcodeID pre) { m_buffer.putByte(pre); } // Word-sized operands / no operand instruction formatters. // // In addition to the opcode, the following operand permutations are supported: // * None - instruction takes no operands. // * One register - the low three bits of the RegisterID are added into the opcode. // * Two registers - encode a register form ModRm (for all ModRm formats, the reg field is passed first, and a GroupOpcodeID may be passed in its place). // * Three argument ModRM - a register, and a register and an offset describing a memory operand. // * Five argument ModRM - a register, and a base register, an index, scale, and offset describing a memory operand. // // For 32-bit x86 targets, the address operand may also be provided as a void*. // On 64-bit targets REX prefixes will be planted as necessary, where high numbered registers are used. // // The twoByteOp methods plant two-byte Intel instructions sequences (first opcode byte 0x0F). void oneByteOp(OneByteOpcodeID opcode) { m_buffer.ensureSpace(maxInstructionSize); m_buffer.putByteUnchecked(opcode); } void oneByteOp(OneByteOpcodeID opcode, RegisterID reg) { m_buffer.ensureSpace(maxInstructionSize); emitRexIfNeeded(0, 0, reg); m_buffer.putByteUnchecked(opcode + (reg & 7)); } void oneByteOp(OneByteOpcodeID opcode, int reg, RegisterID rm) { m_buffer.ensureSpace(maxInstructionSize); emitRexIfNeeded(reg, 0, rm); m_buffer.putByteUnchecked(opcode); registerModRM(reg, rm); } void oneByteOp(OneByteOpcodeID opcode, int reg, RegisterID base, int offset) { m_buffer.ensureSpace(maxInstructionSize); emitRexIfNeeded(reg, 0, base); m_buffer.putByteUnchecked(opcode); memoryModRM(reg, base, offset); } void oneByteOp_disp32(OneByteOpcodeID opcode, int reg, RegisterID base, int offset) { m_buffer.ensureSpace(maxInstructionSize); emitRexIfNeeded(reg, 0, base); m_buffer.putByteUnchecked(opcode); memoryModRM_disp32(reg, base, offset); } void oneByteOp(OneByteOpcodeID opcode, int reg, RegisterID base, RegisterID index, int scale, int offset) { m_buffer.ensureSpace(maxInstructionSize); emitRexIfNeeded(reg, index, base); m_buffer.putByteUnchecked(opcode); memoryModRM(reg, base, index, scale, offset); }#if !PLATFORM(X86_64) void oneByteOp(OneByteOpcodeID opcode, int reg, void* address) { m_buffer.ensureSpace(maxInstructionSize); m_buffer.putByteUnchecked(opcode); memoryModRM(reg, address); }#endif void twoByteOp(TwoByteOpcodeID opcode) { m_buffer.ensureSpace(maxInstructionSize); m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); m_buffer.putByteUnchecked(opcode); } void twoByteOp(TwoByteOpcodeID opcode, int reg, RegisterID rm) { m_buffer.ensureSpace(maxInstructionSize); emitRexIfNeeded(reg, 0, rm); m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); m_buffer.putByteUnchecked(opcode); registerModRM(reg, rm); } void twoByteOp(TwoByteOpcodeID opcode, int reg, RegisterID base, int offset) { m_buffer.ensureSpace(maxInstructionSize); emitRexIfNeeded(reg, 0, base); m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); m_buffer.putByteUnchecked(opcode); memoryModRM(reg, base, offset); } void twoByteOp(TwoByteOpcodeID opcode, int reg, RegisterID base, RegisterID index, int scale, int offset) { m_buffer.ensureSpace(maxInstructionSize); emitRexIfNeeded(reg, index, base); m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); m_buffer.putByteUnchecked(opcode); memoryModRM(reg, base, index, scale, offset); }#if PLATFORM(X86_64) // Quad-word-sized operands: // // Used to format 64-bit operantions, planting a REX.w prefix. // When planting d64 or f64 instructions, not requiring a REX.w prefix, // the normal (non-'64'-postfixed) formatters should be used. void oneByteOp64(OneByteOpcodeID opcode) { m_buffer.ensureSpace(maxInstructionSize); emitRexW(0, 0, 0); m_buffer.putByteUnchecked(opcode); } void oneByteOp64(OneByteOpcodeID opcode, RegisterID reg) { m_buffer.ensureSpace(maxInstructionSize); emitRexW(0, 0, reg); m_buffer.putByteUnchecked(opcode + (reg & 7)); } void oneByteOp64(OneByteOpcodeID opcode, int reg, RegisterID rm) { m_buffer.ensureSpace(maxInstructionSize); emitRexW(reg, 0, rm); m_buffer.putByteUnchecked(opcode); registerModRM(reg, rm); } void oneByteOp64(OneByteOpcodeID opcode, int reg, RegisterID base, int offset) { m_buffer.ensureSpace(maxInstructionSize); emitRexW(reg, 0, base); m_buffer.putByteUnchecked(opcode); memoryModRM(reg, base, offset); } void oneByteOp64_disp32(OneByteOpcodeID opcode, int reg, RegisterID base, int offset) { m_buffer.ensureSpace(maxInstructionSize); emitRexW(reg, 0, base); m_buffer.putByteUnchecked(opcode); memoryModRM_disp32(reg, base, offset); } void oneByteOp64(OneByteOpcodeID opcode, int reg, RegisterID base, RegisterID index, int scale, int offset) { m_buffer.ensureSpace(maxInstructionSize); emitRexW(reg, index, base); m_buffer.putByteUnchecked(opcode); memoryModRM(reg, base, index, scale, offset); } void twoByteOp64(TwoByteOpcodeID opcode, int reg, RegisterID rm) { m_buffer.ensureSpace(maxInstructionSize); emitRexW(reg, 0, rm); m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); m_buffer.putByteUnchecked(opcode); registerModRM(reg, rm); }#endif // Byte-operands: // // These methods format byte operations. Byte operations differ from the normal // formatters in the circumstances under which they will decide to emit REX prefixes. // These should be used where any register operand signifies a byte register. // // The disctinction is due to the handling of register numbers in the range 4..7 on // x86-64. These register numbers may either represent the second byte of the first // four registers (ah..bh) or the first byte of the second four registers (spl..dil). // // Since ah..bh cannot be used in all permutations of operands (specifically cannot // be accessed where a REX prefix is present), these are likely best treated as // deprecated. In order to ensure the correct registers spl..dil are selected a // REX prefix will be emitted for any byte register operand in the range 4..15. // // These formatters may be used in instructions where a mix of operand sizes, in which // case an unnecessary REX will be emitted, for example: // movzbl %al, %edi // In this case a REX will be planted since edi is 7 (and were this a byte operand // a REX would be required to specify dil instead of bh). Unneeded REX prefixes will // be silently ignored by the processor. // // Address operands should still be checked using regRequiresRex(), while byteRegRequiresRex() // is provided to check byte register operands. void oneByteOp8(OneByteOpcodeID opcode, GroupOpcodeID groupOp, RegisterID rm) { m_buffer.ensureSpace(maxInstructionSize); emitRexIf(byteRegRequiresRex(rm), 0, 0, rm); m_buffer.putByteUnchecked(opcode); registerModRM(groupOp, rm); } void twoByteOp8(TwoByteOpcodeID opcode, RegisterID reg, RegisterID rm) { m_buffer.ensureSpace(maxInstructionSize); emitRexIf(byteRegRequiresRex(reg)|byteRegRequiresRex(rm), reg, 0, rm); m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); m_buffer.putByteUnchecked(opcode); registerModRM(reg, rm); } void twoByteOp8(TwoByteOpcodeID opcode, GroupOpcodeID groupOp, RegisterID rm) { m_buffer.ensureSpace(maxInstructionSize); emitRexIf(byteRegRequiresRex(rm), 0, 0, rm); m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); m_buffer.putByteUnchecked(opcode); registerModRM(groupOp, rm); } // Immediates: // // An immedaite should be appended where appropriate after an op has been emitted. // The writes are unchecked since the opcode formatters above will have ensured space. void immediate8(int imm) { m_buffer.putByteUnchecked(imm); } void immediate32(int imm) { m_buffer.putIntUnchecked(imm); } void immediate64(int64_t imm) { m_buffer.putInt64Unchecked(imm); } JmpSrc immediateRel32() { m_buffer.putIntUnchecked(0); return JmpSrc(m_buffer.size()); } // Administrative methods: size_t size() const { return m_buffer.size(); } bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); } void* data() const { return m_buffer.data(); } void* executableCopy(ExecutablePool* allocator) { return m_buffer.executableCopy(allocator); } private: // Internals; ModRm and REX formatters. static const RegisterID noBase = X86::ebp; static const RegisterID hasSib = X86::esp; static const RegisterID noIndex = X86::esp;#if PLATFORM(X86_64) static const RegisterID noBase2 = X86::r13; static const RegisterID hasSib2 = X86::r12; // Registers r8 & above require a REX prefixe. inline bool regRequiresRex(int reg) { return (reg >= X86::r8); } // Byte operand register spl & above require a REX prefix (to prevent the 'H' registers be accessed). inline bool byteRegRequiresRex(int reg) { return (reg >= X86::esp); } // Format a REX prefix byte. inline void emitRex(bool w, int r, int x, int b) { m_buffer.putByteUnchecked(PRE_REX | ((int)w << 3) | ((r>>3)<<2) | ((x>>3)<<1) | (b>>3)); } // Used to plant a REX byte with REX.w set (for 64-bit operations). inline void emitRexW(int r, int x, int b) { emitRex(true, r, x, b); } // Used for operations with byte operands - use byteRegRequiresRex() to check register operands, // regRequiresRex() to check other registers (i.e. address base & index). inline void emitRexIf(bool condition, int r, int x, int b) { if (condition) emitRex(false, r, x, b); } // Used for word sized operations, will plant a REX prefix if necessary (if any register is r8 or above). inline void emitRexIfNeeded(int r, int x, int b) { emitRexIf(regRequiresRex(r) || regRequiresRex(x) || regRequiresRex(b), r, x, b); }#else // No REX prefix bytes on 32-bit x86. inline bool regRequiresRex(int) { return false; } inline bool byteRegRequiresRex(int) { return false; } inline void emitRexIf(bool, int, int, int) {} inline void emitRexIfNeeded(int, int, int) {}#endif enum ModRmMode { ModRmMemoryNoDisp, ModRmMemoryDisp8, ModRmMemoryDisp32, ModRmRegister, }; void putModRm(ModRmMode mode, int reg, RegisterID rm) { m_buffer.putByteUnchecked((mode << 6) | ((reg & 7) << 3) | (rm & 7)); } void putModRmSib(ModRmMode mode, int reg, RegisterID base, RegisterID index, int scale) { ASSERT(mode != ModRmRegister); putModRm(mode, reg, hasSib); m_buffer.putByteUnchecked((scale << 6) | ((index & 7) << 3) | (base & 7)); } void registerModRM(int reg, RegisterID rm) { putModRm(ModRmRegister, reg, rm); } void memoryModRM(int reg, RegisterID base, int offset) { // A base of esp or r12 would be interpreted as a sib, so force a sib with no index & put the base in there.#if PLATFORM(X86_64) if ((base == hasSib) || (base == hasSib2)) {#else if (base == hasSib) {#endif if (!offset) // No need to check if the base is noBase, since we know it is hasSib! putModRmSib(ModRmMemoryNoDisp, reg, base, noIndex, 0); else if (CAN_SIGN_EXTEND_8_32(offset)) { putModRmSib(ModRmMemoryDisp8, reg, base, noIndex, 0); m_buffer.putByteUnchecked(offset); } else { putModRmSib(ModRmMemoryDisp32, reg, base, noIndex, 0); m_buffer.putIntUnchecked(offset); } } else {#if PLATFORM(X86_64) if (!offset && (base != noBase) && (base != noBase2))#else if (!offset && (base != noBase))#endif putModRm(ModRmMemoryNoDisp, reg, base); else if (CAN_SIGN_EXTEND_8_32(offset)) { putModRm(ModRmMemoryDisp8, reg, base); m_buffer.putByteUnchecked(offset); } else { putModRm(ModRmMemoryDisp32, reg, base); m_buffer.putIntUnchecked(offset); } } } void memoryModRM_disp32(int reg, RegisterID base, int offset) { // A base of esp or r12 would be interpreted as a sib, so force a sib with no index & put the base in there.#if PLATFORM(X86_64) if ((base == hasSib) || (base == hasSib2)) {#else if (base == hasSib) {#endif putModRmSib(ModRmMemoryDisp32, reg, base, noIndex, 0); m_buffer.putIntUnchecked(offset); } else { putModRm(ModRmMemoryDisp32, reg, base); m_buffer.putIntUnchecked(offset); } } void memoryModRM(int reg, RegisterID base, RegisterID index, int scale, int offset) { ASSERT(index != noIndex);#if PLATFORM(X86_64) if (!offset && (base != noBase) && (base != noBase2))#else if (!offset && (base != noBase))#endif putModRmSib(ModRmMemoryNoDisp, reg, base, index, scale); else if (CAN_SIGN_EXTEND_8_32(offset)) { putModRmSib(ModRmMemoryDisp8, reg, base, index, scale); m_buffer.putByteUnchecked(offset); } else { putModRmSib(ModRmMemoryDisp32, reg, base, index, scale); m_buffer.putIntUnchecked(offset); } }#if !PLATFORM(X86_64) void memoryModRM(int reg, void* address) { // noBase + ModRmMemoryNoDisp means noBase + ModRmMemoryDisp32! putModRm(ModRmMemoryNoDisp, reg, noBase); m_buffer.putIntUnchecked(reinterpret_cast<int32_t>(address)); }#endif AssemblerBuffer m_buffer; } m_formatter;};} // namespace JSC#endif // ENABLE(ASSEMBLER) && PLATFORM(X86)#endif // X86Assembler_h
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -