diff options
Diffstat (limited to 'Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.cpp')
-rw-r--r-- | Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.cpp | 330 |
1 files changed, 260 insertions, 70 deletions
diff --git a/Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.cpp b/Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.cpp index 0ea817a46..9584f4953 100644 --- a/Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.cpp +++ b/Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,6 +24,9 @@ */ #include "config.h" + +#if USE(ARM64_DISASSEMBLER) + #include "A64DOpcode.h" #include <stdarg.h> @@ -62,6 +65,8 @@ struct OpcodeGroupInitializer { { groupIndex, groupClass::mask, groupClass::pattern, groupClass::format } static OpcodeGroupInitializer opcodeGroupList[] = { + OPCODE_GROUP_ENTRY(0x08, A64DOpcodeLoadStoreRegisterPair), + OPCODE_GROUP_ENTRY(0x09, A64DOpcodeLoadStoreRegisterPair), OPCODE_GROUP_ENTRY(0x0a, A64DOpcodeLogicalShiftedRegister), OPCODE_GROUP_ENTRY(0x0b, A64DOpcodeAddSubtractExtendedRegister), OPCODE_GROUP_ENTRY(0x0b, A64DOpcodeAddSubtractShiftedRegister), @@ -78,6 +83,7 @@ static OpcodeGroupInitializer opcodeGroupList[] = { OPCODE_GROUP_ENTRY(0x15, A64DOpcodeConditionalBranchImmediate), OPCODE_GROUP_ENTRY(0x15, A64DOpcodeCompareAndBranchImmediate), OPCODE_GROUP_ENTRY(0x15, A64DOpcodeHint), + OPCODE_GROUP_ENTRY(0x15, A64DOpcodeDmb), OPCODE_GROUP_ENTRY(0x16, A64DOpcodeUnconditionalBranchImmediate), OPCODE_GROUP_ENTRY(0x16, A64DOpcodeUnconditionalBranchRegister), OPCODE_GROUP_ENTRY(0x16, A64DOpcodeTestAndBranchImmediate), @@ -88,12 +94,14 @@ static OpcodeGroupInitializer opcodeGroupList[] = { OPCODE_GROUP_ENTRY(0x18, A64DOpcodeLoadStoreRegisterOffset), OPCODE_GROUP_ENTRY(0x19, A64DOpcodeLoadStoreUnsignedImmediate), OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeConditionalSelect), + OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeDataProcessing1Source), OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeDataProcessing2Source), OPCODE_GROUP_ENTRY(0x1b, A64DOpcodeDataProcessing3Source), OPCODE_GROUP_ENTRY(0x1c, A64DOpcodeLoadStoreImmediate), OPCODE_GROUP_ENTRY(0x1c, A64DOpcodeLoadStoreRegisterOffset), OPCODE_GROUP_ENTRY(0x1d, A64DOpcodeLoadStoreUnsignedImmediate), OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointCompare), + OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointConditionalSelect), OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointDataProcessing2Source), OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointDataProcessing1Source), OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingFixedPointConversions), @@ -172,6 +180,11 @@ const char* A64DOpcode::format() void A64DOpcode::appendRegisterName(unsigned registerNumber, bool is64Bit) { + if (registerNumber == 29) { + bufferPrintf(is64Bit ? "fp" : "wfp"); + return; + } + if (registerNumber == 30) { bufferPrintf(is64Bit ? "lr" : "wlr"); return; @@ -276,7 +289,7 @@ const char* const A64DOpcodeBitfield::s_opNames[3] = { "sbfm", "bfm", "ubfm" }; const char* const A64DOpcodeBitfield::s_extendPseudoOpNames[3][3] = { { "sxtb", "sxth", "sxtw" }, { 0, 0, 0} , { "uxtb", "uxth", "uxtw" } }; const char* const A64DOpcodeBitfield::s_insertOpNames[3] = { "sbfiz", "bfi", "ubfiz" }; -const char* const A64DOpcodeBitfield::s_extractOpNames[3] = { "sbfx", "bf", "ubfx" }; +const char* const A64DOpcodeBitfield::s_extractOpNames[3] = { "sbfx", "bfxil", "ubfx" }; const char* A64DOpcodeBitfield::format() { @@ -298,7 +311,7 @@ const char* A64DOpcodeBitfield::format() } else if (immediateS() == 15) { appendInstructionName(extendPseudoOpNames(1)); isSTXType = true; - } else if (immediateS() == 31 && is64Bit()) { + } else if (immediateS() == 31 && is64Bit() && !opc()) { appendInstructionName(extendPseudoOpNames(2)); isSTXType = true; } @@ -312,19 +325,9 @@ const char* A64DOpcodeBitfield::format() } } - if (opc() == 0x2 && immediateS() == (immediateR() + 1)) { - // lsl - appendInstructionName("lsl"); - appendRegisterName(rd(), is64Bit()); - appendSeparator(); - appendRegisterName(rn(), is64Bit()); - appendSeparator(); - appendUnsignedImmediate((is64Bit() ? 63u : 31u) - immediateR()); - - return m_formatBuffer; - } else if (!(opc() & 0x1) && ((immediateS() & 0x1f) == 0x1f) && (is64Bit() == (immediateS() >> 5))) { + if (!(opc() & 0x1) && ((immediateS() & 0x1f) == 0x1f) && (is64Bit() == (immediateS() >> 5))) { // asr/lsr - appendInstructionName(!opc() ? "ars" : "lsr"); + appendInstructionName(!opc() ? "asr" : "lsr"); appendRegisterName(rd(), is64Bit()); appendSeparator(); @@ -333,42 +336,58 @@ const char* A64DOpcodeBitfield::format() appendUnsignedImmediate(immediateR()); return m_formatBuffer; - } else if (immediateS() < immediateR()) { - // bit field insert - appendInstructionName(insertOpNames()); + } + if (opc() == 0x2 && (immediateS() + 1) == immediateR()) { + // lsl + appendInstructionName("lsl"); appendRegisterName(rd(), is64Bit()); appendSeparator(); appendRegisterName(rn(), is64Bit()); appendSeparator(); appendUnsignedImmediate((is64Bit() ? 64u : 32u) - immediateR()); - appendSeparator(); - appendUnsignedImmediate(immediateS() + 1); - + return m_formatBuffer; - } else { - // bit field extract - appendInstructionName(extractOpNames()); + } + + if (immediateS() < immediateR()) { + if (opc() != 1 || rn() != 0x1f) { + // bit field insert + appendInstructionName(insertOpNames()); + appendRegisterName(rd(), is64Bit()); + appendSeparator(); + appendRegisterName(rn(), is64Bit()); + appendSeparator(); + appendUnsignedImmediate((is64Bit() ? 64u : 32u) - immediateR()); + appendSeparator(); + appendUnsignedImmediate(immediateS() + 1); + + return m_formatBuffer; + } + + appendInstructionName(opName()); appendRegisterName(rd(), is64Bit()); appendSeparator(); appendRegisterName(rn(), is64Bit()); appendSeparator(); appendUnsignedImmediate(immediateR()); appendSeparator(); - appendUnsignedImmediate(immediateS() - immediateR() + 1); - + appendUnsignedImmediate(immediateS()); + return m_formatBuffer; } + + // bit field extract + appendInstructionName(extractOpNames()); - appendInstructionName(opName()); appendRegisterName(rd(), is64Bit()); appendSeparator(); appendRegisterName(rn(), is64Bit()); appendSeparator(); appendUnsignedImmediate(immediateR()); appendSeparator(); - appendUnsignedImmediate(immediateS()); + appendUnsignedImmediate(immediateS() - immediateR() + 1); return m_formatBuffer; } @@ -430,6 +449,38 @@ const char* A64DOpcodeConditionalSelect::format() } +const char* const A64DOpcodeDataProcessing1Source::s_opNames[8] = { + "rbit", "rev16", "rev32", "rev", "clz", "cls", 0, 0 +}; + +const char* A64DOpcodeDataProcessing1Source::format() +{ + if (sBit()) + return A64DOpcode::format(); + + if (opCode2()) + return A64DOpcode::format(); + + if (opCode() & 0x38) + return A64DOpcode::format(); + + if ((opCode() & 0x3e) == 0x6) + return A64DOpcode::format(); + + if (is64Bit() && opCode() == 0x3) + return A64DOpcode::format(); + + if (!is64Bit() && opCode() == 0x2) + appendInstructionName("rev"); + else + appendInstructionName(opName()); + appendZROrRegisterName(rd(), is64Bit()); + appendSeparator(); + appendZROrRegisterName(rn(), is64Bit()); + + return m_formatBuffer; +} + const char* const A64DOpcodeDataProcessing2Source::s_opNames[8] = { 0, 0, "udiv", "sdiv", "lsl", "lsr", "asr", "ror" // We use the pseudo-op names for the shift/rotate instructions }; @@ -449,11 +500,11 @@ const char* A64DOpcodeDataProcessing2Source::format() return A64DOpcode::format(); appendInstructionName(opName()); - appendRegisterName(rd(), is64Bit()); + appendZROrRegisterName(rd(), is64Bit()); appendSeparator(); - appendRegisterName(rn(), is64Bit()); + appendZROrRegisterName(rn(), is64Bit()); appendSeparator(); - appendRegisterName(rm(), is64Bit()); + appendZROrRegisterName(rm(), is64Bit()); return m_formatBuffer; } @@ -482,15 +533,18 @@ const char* A64DOpcodeDataProcessing3Source::format() if (!opName()) return A64DOpcode::format(); + if ((opNum() & 0x4) && (ra() != 31)) + return A64DOpcode::format(); + appendInstructionName(opName()); - appendRegisterName(rd(), is64Bit()); + appendZROrRegisterName(rd(), is64Bit()); appendSeparator(); bool srcOneAndTwoAre64Bit = is64Bit() & !(opNum() & 0x2); - appendRegisterName(rn(), srcOneAndTwoAre64Bit); + appendZROrRegisterName(rn(), srcOneAndTwoAre64Bit); appendSeparator(); - appendRegisterName(rm(), srcOneAndTwoAre64Bit); + appendZROrRegisterName(rm(), srcOneAndTwoAre64Bit); - if ((ra() != 31) || !(opNum() & 0x4)) { + if (ra() != 31) { appendSeparator(); appendRegisterName(ra(), is64Bit()); } @@ -550,23 +604,26 @@ const char* A64OpcodeExceptionGeneration::format() const char* A64DOpcodeExtract::format() { - if (!op21() || !o0Bit()) + if (op21() || o0Bit()) return A64DOpcode::format(); if (is64Bit() != nBit()) return A64DOpcode::format(); - if (is64Bit() && (immediateS() & 0x20)) + if (!is64Bit() && (immediateS() & 0x20)) return A64DOpcode::format(); - const char* opName = (rn() == rm()) ? "ror" : "extr"; + bool isROR = rn() == rm(); + const char* opName = (isROR) ? "ror" : "extr"; appendInstructionName(opName); - appendRegisterName(rd(), is64Bit()); + appendZROrRegisterName(rd(), is64Bit()); appendSeparator(); - appendRegisterName(rn(), is64Bit()); - appendSeparator(); - appendRegisterName(rm(), is64Bit()); + appendZROrRegisterName(rn(), is64Bit()); + if (!isROR) { + appendSeparator(); + appendZROrRegisterName(rm(), is64Bit()); + } appendSeparator(); appendUnsignedImmediate(immediateS()); @@ -602,6 +659,30 @@ const char* A64DOpcodeFloatingPointCompare::format() return m_formatBuffer; } +const char* A64DOpcodeFloatingPointConditionalSelect::format() +{ + if (mBit()) + return A64DOpcode::format(); + + if (sBit()) + return A64DOpcode::format(); + + if (type() & 0x2) + return A64DOpcode::format(); + + appendInstructionName(opName()); + unsigned registerSize = type() + 2; + appendFPRegisterName(rd(), registerSize); + appendSeparator(); + appendFPRegisterName(rn(), registerSize); + appendSeparator(); + appendFPRegisterName(rm(), registerSize); + appendSeparator(); + appendString(conditionName(condition())); + + return m_formatBuffer; +} + const char* const A64DOpcodeFloatingPointDataProcessing1Source::s_opNames[16] = { "fmov", "fabs", "fneg", "fsqrt", "fcvt", "fcvt", 0, "fcvt", "frintn", "frintp", "frintm", "frintz", "frinta", 0, "frintx", "frinti" @@ -770,10 +851,10 @@ const char* A64DOpcodeFloatingPointIntegerConversions::format() // fmov Vd.D[1], Xn bufferPrintf("V%u.D[1]", rd()); appendSeparator(); - appendRegisterName(rn()); + appendZROrRegisterName(rn()); } else { // fmov Xd, Vn.D[1] - appendRegisterName(rd()); + appendZROrRegisterName(rd()); appendSeparator(); bufferPrintf("V%u.D[1]", rn()); } @@ -788,9 +869,9 @@ const char* A64DOpcodeFloatingPointIntegerConversions::format() if (destIsFP) { appendFPRegisterName(rd(), FPRegisterSize); appendSeparator(); - appendRegisterName(rn(), is64Bit()); + appendZROrRegisterName(rn(), is64Bit()); } else { - appendRegisterName(rd(), is64Bit()); + appendZROrRegisterName(rd(), is64Bit()); appendSeparator(); appendFPRegisterName(rn(), FPRegisterSize); } @@ -812,6 +893,23 @@ const char* A64DOpcodeHint::format() return m_formatBuffer; } +const char* const A64DOpcodeDmb::s_optionNames[16] = { + 0, "oshld", "oshst", "osh", 0, "nshld", "nshst", "nsh", + 0, "ishld", "ishst", "ish", 0, "ld", "st", "sy" +}; + +const char* A64DOpcodeDmb::format() +{ + appendInstructionName(opName()); + const char* thisOption = option(); + if (thisOption) + appendString(thisOption); + else + appendUnsignedImmediate(crM()); + + return m_formatBuffer; +} + // A zero in an entry of the table means the instruction is Unallocated const char* const A64DOpcodeLoadStore::s_opNames[32] = { "strb", "ldrb", "ldrsb", "ldrsb", "str", "ldr", "str", "ldr", @@ -853,6 +951,8 @@ const char* A64DOpcodeLoadStoreImmediate::format() appendInstructionName(thisOpName); if (vBit()) appendFPRegisterName(rt(), size()); + else if (!opc()) + appendZROrRegisterName(rt(), is64BitRT()); else appendRegisterName(rt(), is64BitRT()); appendSeparator(); @@ -910,31 +1010,99 @@ const char* A64DOpcodeLoadStoreRegisterOffset::format() appendFPRegisterName(rt(), size()); scale = ((opc() & 2)<<1) | size(); } else { - appendRegisterName(rt(), is64BitRT()); + if (!opc()) + appendZROrRegisterName(rt(), is64BitRT()); + else + appendRegisterName(rt(), is64BitRT()); scale = size(); } appendSeparator(); appendCharacter('['); appendSPOrRegisterName(rn()); - appendSeparator(); - appendZROrRegisterName(rm(), (option() & 0x3) == 0x3); + if (rm() != 31) { + appendSeparator(); + appendRegisterName(rm(), (option() & 0x3) == 0x3); - unsigned shift = sBit() ? scale : 0; + unsigned shift = sBit() ? scale : 0; - if (option() == 0x3) { - if (shift) { + if (option() == 0x3) { + if (shift) { + appendSeparator(); + appendString("lsl "); + appendUnsignedImmediate(shift); + } + } else { appendSeparator(); - appendString("lsl "); - appendUnsignedImmediate(shift); + appendString(optionName()); + if (shift) + appendUnsignedImmediate(shift); } + } + + appendCharacter(']'); + + return m_formatBuffer; +} + +const char* A64DOpcodeLoadStoreRegisterPair::opName() +{ + if (!vBit() && lBit() && size() == 0x1) + return "ldpsw"; + if (lBit()) + return "ldp"; + return "stp"; +} + +const char* A64DOpcodeLoadStoreRegisterPair::format() +{ + const char* thisOpName = opName(); + + if (size() == 0x3) + return A64DOpcode::format(); + + if ((offsetMode() < 0x1) || (offsetMode() > 0x3)) + return A64DOpcode::format(); + + if ((offsetMode() == 0x1) && !vBit() && !lBit()) + return A64DOpcode::format(); + + appendInstructionName(thisOpName); + unsigned offsetShift; + if (vBit()) { + appendFPRegisterName(rt(), size()); + appendSeparator(); + appendFPRegisterName(rt2(), size()); + offsetShift = size() + 2; } else { + if (!lBit()) + appendZROrRegisterName(rt(), is64Bit()); + else + appendRegisterName(rt(), is64Bit()); appendSeparator(); - appendString(optionName()); - if (shift) - appendUnsignedImmediate(shift); + if (!lBit()) + appendZROrRegisterName(rt2(), is64Bit()); + else + appendRegisterName(rt2(), is64Bit()); + offsetShift = (size() >> 1) + 2; } - appendCharacter(']'); + appendSeparator(); + appendCharacter('['); + appendSPOrRegisterName(rn()); + + int offset = immediate7() << offsetShift; + + if (offsetMode() == 1) { + appendCharacter(']'); + appendSeparator(); + appendSignedImmediate(offset); + } else { + appendSeparator(); + appendSignedImmediate(offset); + appendCharacter(']'); + if (offsetMode() == 0x3) + appendCharacter('!'); + } return m_formatBuffer; } @@ -952,7 +1120,10 @@ const char* A64DOpcodeLoadStoreUnsignedImmediate::format() appendFPRegisterName(rt(), size()); scale = ((opc() & 2)<<1) | size(); } else { - appendRegisterName(rt(), is64BitRT()); + if (!opc()) + appendZROrRegisterName(rt(), is64BitRT()); + else + appendRegisterName(rt(), is64BitRT()); scale = size(); } appendSeparator(); @@ -983,15 +1154,15 @@ const char* A64DOpcodeLogicalShiftedRegister::format() appendInstructionName("tst"); else { if (isMov()) - appendInstructionName("mov"); + appendInstructionName(nBit() ? "mvn" : "mov"); else appendInstructionName(opName(opNumber())); - appendSPOrRegisterName(rd(), is64Bit()); + appendZROrRegisterName(rd(), is64Bit()); appendSeparator(); } if (!isMov()) { - appendRegisterName(rn(), is64Bit()); + appendZROrRegisterName(rn(), is64Bit()); appendSeparator(); } @@ -1075,22 +1246,39 @@ const char* A64DOpcodeLogicalImmediate::format() return m_formatBuffer; } -const char* const A64DOpcodeMoveWide::s_opNames[4] = { "movn", "", "movz", "movk" }; +const char* const A64DOpcodeMoveWide::s_opNames[4] = { "movn", 0, "movz", "movk" }; const char* A64DOpcodeMoveWide::format() { if (opc() == 1) return A64DOpcode::format(); - if (!size() && hw() >= 2) + if (!is64Bit() && hw() >= 2) return A64DOpcode::format(); - appendInstructionName(opName()); - appendRegisterName(rd(), is64Bit()); - appendSeparator(); - appendUnsignedImmediate(immediate16()); - if (hw()) { + if (!opc() && (!immediate16() || !hw()) && (is64Bit() || immediate16() != 0xffff)) { + // MOV pseudo op for MOVN + appendInstructionName("mov"); + appendRegisterName(rd(), is64Bit()); appendSeparator(); - appendShiftAmount(hw()); + + if (is64Bit()) { + int64_t amount = immediate16() << (hw() * 16); + amount = ~amount; + appendSignedImmediate64(amount); + } else { + int32_t amount = immediate16() << (hw() * 16); + amount = ~amount; + appendSignedImmediate(amount); + } + } else { + appendInstructionName(opName()); + appendRegisterName(rd(), is64Bit()); + appendSeparator(); + appendUnsignedHexImmediate(immediate16()); + if (hw()) { + appendSeparator(); + appendShiftAmount(hw()); + } } return m_formatBuffer; @@ -1130,3 +1318,5 @@ const char* A64DOpcodeUnconditionalBranchRegister::format() } } } // namespace JSC::ARM64Disassembler + +#endif // USE(ARM64_DISASSEMBLER) |