From 14880b53c4c18f392d487495ec11ff855d875c12 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Mon, 11 Jul 2022 12:40:19 -0700 Subject: [PATCH] Create and use LZCOUNT Pcode op --- .../src/decompile/cpp/coreaction.cc | 1 + .../Decompiler/src/decompile/cpp/dynamic.cc | 3 +- .../Decompiler/src/decompile/cpp/op.cc | 4 + .../src/decompile/cpp/opbehavior.cc | 6 ++ .../src/decompile/cpp/opbehavior.hh | 7 ++ .../Decompiler/src/decompile/cpp/opcodes.cc | 6 +- .../Decompiler/src/decompile/cpp/opcodes.hh | 3 +- .../Decompiler/src/decompile/cpp/printc.hh | 1 + .../src/decompile/cpp/printlanguage.hh | 1 + .../src/decompile/cpp/slgh_compile.cc | 3 + .../Decompiler/src/decompile/cpp/slghparse.y | 3 +- .../Decompiler/src/decompile/cpp/slghscan.l | 1 + .../Decompiler/src/decompile/cpp/typeop.cc | 8 ++ .../Decompiler/src/decompile/cpp/typeop.hh | 7 ++ .../Decompiler/src/main/doc/pcoderef.xml | 75 ++++++++++++++++--- .../Decompiler/src/main/doc/sleigh.xml | 11 ++- .../callother/CountLeadingOnesOpBehavior.java | 57 -------------- .../CountLeadingZerosOpBehavior.java | 60 --------------- .../pcode/opbehavior/OpBehaviorFactory.java | 1 + .../pcode/opbehavior/OpBehaviorLzcount.java | 48 ++++++++++++ .../ghidra/pcodeCPort/opcodes/OpCode.java | 6 +- .../pcodeCPort/slgh_compile/PcodeCompile.java | 6 ++ .../program/model/pcode/DynamicHash.java | 2 +- .../ghidra/program/model/pcode/PcodeOp.java | 5 +- .../68000/data/languages/68000.pspec | 1 - .../68000/data/languages/68000.sinc | 4 +- .../m68kEmulateInstructionStateModifier.java | 5 -- Ghidra/Processors/ARM/data/languages/ARM.sinc | 1 - .../data/languages/ARMTHUMBinstructions.sinc | 2 +- .../ARM/data/languages/ARMinstructions.sinc | 2 +- .../ARMEmulateInstructionStateModifier.java | 4 - .../Processors/MIPS/data/languages/mips.sinc | 6 -- .../data/languages/mips32Instructions.sinc | 8 +- .../data/languages/mips64Instructions.sinc | 4 +- .../MIPS/data/languages/mipsmicro.sinc | 8 +- .../MIPSEmulateInstructionStateModifier.java | 9 --- .../PowerPC/data/languages/ppc_common.sinc | 1 - .../data/languages/ppc_instructions.sinc | 8 +- .../PPCEmulateInstructionStateModifier.java | 2 - .../tricore/data/languages/tricore.sinc | 12 ++- .../Processors/x86/data/languages/lzcnt.sinc | 47 ++---------- .../src/ghidra/xtext/sleigh/Sleigh.xtext | 3 +- .../languages/html/pcodedescription.html | 43 +++++++++++ GhidraDocs/languages/html/pcoderef.html | 24 +++--- GhidraDocs/languages/html/reference.html | 5 ++ GhidraDocs/languages/html/sleigh.html | 5 +- GhidraDocs/languages/html/sleigh_ref.html | 6 ++ 47 files changed, 288 insertions(+), 247 deletions(-) delete mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/emulate/callother/CountLeadingOnesOpBehavior.java delete mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/emulate/callother/CountLeadingZerosOpBehavior.java create mode 100644 Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/opbehavior/OpBehaviorLzcount.java diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc index 5efffd2de4..24b171e4d9 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc @@ -3617,6 +3617,7 @@ void ActionDeadCode::propagateConsumed(vector &worklist) pushConsumed(b,op->getIn(2), worklist); break; case CPUI_POPCOUNT: + case CPUI_LZCOUNT: a = 16 * op->getIn(0)->getSize() - 1; // Mask for possible bits that could be set a &= outc; // Of the bits that could be set, which are consumed b = (a == 0) ? 0 : ~((uintb)0); // if any consumed, treat all input bits as consumed diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/dynamic.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/dynamic.cc index 3656c0df58..562584d8ef 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/dynamic.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/dynamic.cc @@ -55,7 +55,8 @@ const uint4 DynamicHash::transtable[] = { 0, // CAST is skipped CPUI_INT_ADD, CPUI_INT_ADD, // PTRADD and PTRSUB hash same as INT_ADD - CPUI_SEGMENTOP, CPUI_CPOOLREF, CPUI_NEW, CPUI_INSERT, CPUI_EXTRACT, CPUI_POPCOUNT + CPUI_SEGMENTOP, CPUI_CPOOLREF, CPUI_NEW, CPUI_INSERT, CPUI_EXTRACT, + CPUI_POPCOUNT, CPUI_LZCOUNT }; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc index 3c19cae79a..bb87c7bc73 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc @@ -645,6 +645,10 @@ uintb PcodeOp::getNZMaskLocal(bool cliploop) const resmask = coveringmask((uintb)sz1); resmask &= fullmask; break; + case CPUI_LZCOUNT: + resmask = coveringmask(getIn(0)->getSize() * 8); + resmask &= fullmask; + break; case CPUI_SUBPIECE: resmask = getIn(0)->getNZMask(); sz1 = (int4)getIn(1)->getOffset(); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/opbehavior.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/opbehavior.cc index 3b84bac6a5..bbf2de8f5f 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/opbehavior.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/opbehavior.cc @@ -102,6 +102,7 @@ void OpBehavior::registerInstructions(vector &inst,const Translate inst[CPUI_INSERT] = new OpBehavior(CPUI_INSERT,false); inst[CPUI_EXTRACT] = new OpBehavior(CPUI_EXTRACT,false); inst[CPUI_POPCOUNT] = new OpBehaviorPopcount(); + inst[CPUI_LZCOUNT] = new OpBehaviorLzcount(); } /// \param sizeout is the size of the output in bytes @@ -757,3 +758,8 @@ uintb OpBehaviorPopcount::evaluateUnary(int4 sizeout,int4 sizein,uintb in1) cons return (uintb)popcount(in1); } +uintb OpBehaviorLzcount::evaluateUnary(int4 sizeout,int4 sizein,uintb in1) const + +{ + return (uintb)(count_leading_zeros(in1) - 8*(sizeof(uintb) - sizein)); +} diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/opbehavior.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/opbehavior.hh index 5061cb65fe..b7a4c04091 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/opbehavior.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/opbehavior.hh @@ -511,4 +511,11 @@ public: virtual uintb evaluateUnary(int4 sizeout,int4 sizein,uintb in1) const; }; +/// CPUI_LZCOUNT behavior +class OpBehaviorLzcount : public OpBehavior { +public: + OpBehaviorLzcount(void) : OpBehavior(CPUI_LZCOUNT,true) {} ///< Constructor + virtual uintb evaluateUnary(int4 sizeout,int4 sizein,uintb in1) const; +}; + #endif diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/opcodes.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/opcodes.cc index d116fe62da..1c1a1ea272 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/opcodes.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/opcodes.cc @@ -42,14 +42,14 @@ static const char *opcode_name[] = { "TRUNC", "CEIL", "FLOOR", "ROUND", "BUILD", "DELAY_SLOT", "PIECE", "SUBPIECE", "CAST", "LABEL", "CROSSBUILD", "SEGMENTOP", "CPOOLREF", "NEW", - "INSERT", "EXTRACT", "POPCOUNT" + "INSERT", "EXTRACT", "POPCOUNT", "LZCOUNT" }; static const int4 opcode_indices[] = { - 0, 39, 37, 40, 38, 4, 6, 60, 7, 8, 9, 64, 5, 57, 1, 68, 66, + 0, 39, 37, 40, 38, 4, 6, 60, 7, 8, 9, 64, 5, 57, 1, 68, 66, 61, 71, 55, 52, 47, 48, 41, 43, 44, 49, 46, 51, 42, 53, 50, 58, 70, 54, 24, 19, 27, 21, 33, 11, 29, 15, 16, 32, 25, 12, 28, 35, 30, - 23, 22, 34, 18, 13, 14, 36, 31, 20, 26, 17, 65, 2, 69, 62, 72, 10, 59, + 23, 22, 34, 18, 13, 14, 36, 31, 20, 26, 17, 65, 2, 73, 69, 62, 72, 10, 59, 67, 3, 63, 56, 45 }; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/opcodes.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/opcodes.hh index 7c5cc64c54..e06bcd4ae0 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/opcodes.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/opcodes.hh @@ -123,8 +123,9 @@ enum OpCode { CPUI_INSERT = 70, ///< Insert a bit-range CPUI_EXTRACT = 71, ///< Extract a bit-range CPUI_POPCOUNT = 72, ///< Count the 1-bits + CPUI_LZCOUNT = 73, ///< Count the leading 0-bits - CPUI_MAX = 73 ///< Value indicating the end of the op-code values + CPUI_MAX = 74 ///< Value indicating the end of the op-code values }; extern const char *get_opname(OpCode opc); ///< Convert an OpCode to the name as a string diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh index 6c7d799888..f8d1e93092 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh @@ -329,6 +329,7 @@ public: virtual void opInsertOp(const PcodeOp *op); virtual void opExtractOp(const PcodeOp *op); virtual void opPopcountOp(const PcodeOp *op) { opFunc(op); } + virtual void opLzcountOp(const PcodeOp *op) { opFunc(op); } }; /// \brief Set of print commands for displaying an open brace '{' and setting a new indent level diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printlanguage.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/printlanguage.hh index 497e968c70..5a182b39dc 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printlanguage.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printlanguage.hh @@ -554,6 +554,7 @@ public: virtual void opInsertOp(const PcodeOp *op)=0; ///< Emit an INSERT operator virtual void opExtractOp(const PcodeOp *op)=0; ///< Emit an EXTRACT operator virtual void opPopcountOp(const PcodeOp *op)=0; ///< Emit a POPCOUNT operator + virtual void opLzcountOp(const PcodeOp *op)=0; ///< Emit a LZCOUNT operator virtual string unnamedField(int4 off,int4 size); ///< Generate an artificial field name static int4 mostNaturalBase(uintb val); ///< Determine the most natural base for an integer diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slgh_compile.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/slgh_compile.cc index fb9e94d34b..b997730255 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/slgh_compile.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slgh_compile.cc @@ -785,6 +785,9 @@ void ConsistencyChecker::printOpName(ostream &s,OpTpl *op) case CPUI_POPCOUNT: s << "Count bits(popcount)"; break; + case CPUI_LZCOUNT: + s << "Count leading zero bits(lzcount)"; + break; default: break; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slghparse.y b/Ghidra/Features/Decompiler/src/decompile/cpp/slghparse.y index b3fedb7b6e..51edd86129 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/slghparse.y +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slghparse.y @@ -94,7 +94,7 @@ %right '!' '~' %token OP_ZEXT OP_CARRY OP_BORROW OP_SEXT OP_SCARRY OP_SBORROW OP_NAN OP_ABS %token OP_SQRT OP_CEIL OP_FLOOR OP_ROUND OP_INT2FLOAT OP_FLOAT2FLOAT -%token OP_TRUNC OP_CPOOLREF OP_NEW OP_POPCOUNT +%token OP_TRUNC OP_CPOOLREF OP_NEW OP_POPCOUNT OP_LZCOUNT %token BADINTEGER GOTO_KEY CALL_KEY RETURN_KEY IF_KEY %token DEFINE_KEY ATTACH_KEY MACRO_KEY SPACE_KEY TYPE_KEY RAM_KEY DEFAULT_KEY @@ -444,6 +444,7 @@ expr: varnode { $$ = new ExprTree($1); } | OP_NEW '(' expr ')' { $$ = slgh->pcode.createOp(CPUI_NEW,$3); } | OP_NEW '(' expr ',' expr ')' { $$ = slgh->pcode.createOp(CPUI_NEW,$3,$5); } | OP_POPCOUNT '(' expr ')' { $$ = slgh->pcode.createOp(CPUI_POPCOUNT,$3); } + | OP_LZCOUNT '(' expr ')' { $$ = slgh->pcode.createOp(CPUI_LZCOUNT,$3); } | specificsymbol '(' integervarnode ')' { $$ = slgh->pcode.createOp(CPUI_SUBPIECE,new ExprTree($1->getVarnode()),new ExprTree($3)); } | specificsymbol ':' INTEGER { $$ = slgh->pcode.createBitRange($1,0,(uint4)(*$3 * 8)); delete $3; } | specificsymbol '[' INTEGER ',' INTEGER ']' { $$ = slgh->pcode.createBitRange($1,(uint4)*$3,(uint4)*$5); delete $3, delete $5; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slghscan.l b/Ghidra/Features/Decompiler/src/decompile/cpp/slghscan.l index 2df137019f..58e0a1dca3 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/slghscan.l +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slghscan.l @@ -641,6 +641,7 @@ with { BEGIN(pattern); withsection = 1; slgh->calcContextLayout(); return WITH cpool { return OP_CPOOLREF; } newobject { return OP_NEW; } popcount { return OP_POPCOUNT; } +lzcount { return OP_LZCOUNT; } if { return IF_KEY; } goto { return GOTO_KEY; } call { return CALL_KEY; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc index 704950e036..e57728510c 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc @@ -102,6 +102,7 @@ void TypeOp::registerInstructions(vector &inst,TypeFactory *tlst, inst[CPUI_INSERT] = new TypeOpInsert(tlst); inst[CPUI_EXTRACT] = new TypeOpExtract(tlst); inst[CPUI_POPCOUNT] = new TypeOpPopcount(tlst); + inst[CPUI_LZCOUNT] = new TypeOpLzcount(tlst); } /// Change basic data-type info (signed vs unsigned) and operator names ( '>>' vs '>>>' ) @@ -2323,3 +2324,10 @@ TypeOpPopcount::TypeOpPopcount(TypeFactory *t) opflags = PcodeOp::unary; behave = new OpBehaviorPopcount(); } + +TypeOpLzcount::TypeOpLzcount(TypeFactory *t) + : TypeOpFunc(t,CPUI_LZCOUNT,"LZCOUNT",TYPE_INT,TYPE_UNKNOWN) +{ + opflags = PcodeOp::unary; + behave = new OpBehaviorLzcount(); +} diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.hh index 7c9532cdc2..78af793ead 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.hh @@ -857,4 +857,11 @@ public: virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opPopcountOp(op); } }; +/// \brief Information about the LZCOUNT op-code +class TypeOpLzcount : public TypeOpFunc { +public: + TypeOpLzcount(TypeFactory *t); ///< Constructor + virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opLzcountOp(op); } +}; + #endif diff --git a/Ghidra/Features/Decompiler/src/main/doc/pcoderef.xml b/Ghidra/Features/Decompiler/src/main/doc/pcoderef.xml index 6c1394dbb2..5dbad3a82d 100644 --- a/Ghidra/Features/Decompiler/src/main/doc/pcoderef.xml +++ b/Ghidra/Features/Decompiler/src/main/doc/pcoderef.xml @@ -2,7 +2,7 @@
P-Code Reference Manual - Last updated September 5, 2019 + Last updated March 2, 2023 @@ -22,7 +22,7 @@ -P + @@ -90,52 +90,58 @@ - + - + - + - + - + - + - + - + + + + + + +
INT_SUB FLOAT_EQUAL
STORE INT_CARRY
INT_EQUALLZCOUNT INT_MULT FLOAT_FLOOR
INT_NOTEQUALINT_EQUAL INT_DIV FLOAT_ROUND
INT_LESSINT_NOTEQUAL INT_REM FLOAT_NAN
INT_SLESSINT_LESS INT_SDIV INT2FLOAT
INT_LESSEQUALINT_SLESS INT_SREM FLOAT2FLOAT
INT_SLESSEQUALINT_LESSEQUAL BOOL_NEGATE TRUNC
INT_ZEXTINT_SLESSEQUAL BOOL_XOR CPOOLREF
INT_SEXTINT_ZEXT BOOL_AND NEW
INT_SEXT
@@ -977,6 +983,50 @@ count is zero extended into the output varnode. +LZCOUNT + + ++++ + + + + + + + + + + + + + + + + + + + + + + + +
ParametersDescription
input0 + Input varnode to count.
output + Resulting integer varnode containing count.
Semantic statement +
+ output = lzcount(input0);
+
+ +This operator counts the number of zeros starting at the most significant bit. +For instance, for a 4-byte varnode, a value of 0 returns 32, a value of 1 +returns 31, and the value 231 returns 0. +The resulting count is zero extended into the output varnode. + +
+ INT_EQUAL @@ -4058,6 +4108,11 @@ to SLEIGH bitrange syntax such as output = inpu + + + + + diff --git a/Ghidra/Features/Decompiler/src/main/doc/sleigh.xml b/Ghidra/Features/Decompiler/src/main/doc/sleigh.xml index e9fc067f91..1b581cc83f 100644 --- a/Ghidra/Features/Decompiler/src/main/doc/sleigh.xml +++ b/Ghidra/Features/Decompiler/src/main/doc/sleigh.xml @@ -4,7 +4,7 @@ SLEIGHA Language for Rapid Processor SpecificationOriginally published December 16, 2005 - Last updated August 24, 2022 + Last updated March 2, 2023 @@ -279,7 +279,8 @@ general purpose processor instruction sets. They break up into groups. - + @@ -3856,6 +3857,12 @@ to lowest. + + + + + diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/emulate/callother/CountLeadingOnesOpBehavior.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/emulate/callother/CountLeadingOnesOpBehavior.java deleted file mode 100644 index 196f438a13..0000000000 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/emulate/callother/CountLeadingOnesOpBehavior.java +++ /dev/null @@ -1,57 +0,0 @@ -/* ### - * IP: GHIDRA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.pcode.emulate.callother; - -import ghidra.pcode.emulate.Emulate; -import ghidra.pcode.memstate.MemoryState; -import ghidra.pcodeCPort.error.LowlevelError; -import ghidra.program.model.pcode.Varnode; - -public class CountLeadingOnesOpBehavior implements OpBehaviorOther { - - @Override - public void evaluate(Emulate emu, Varnode out, Varnode[] inputs) { - - if (out == null) { - throw new LowlevelError("CALLOTHER: Count Leading Ones op missing required output"); - } - - if (inputs.length != 2 || inputs[1].getSize() == 0 || inputs[1].isConstant()) { - throw new LowlevelError( - "CALLOTHER: Count Leading Ones op requires one non-constant varnode input"); - } - - // TODO: add support for larger varnode sizes - - Varnode in = inputs[1]; - if (in.getSize() > 8 || out.getSize() > 8) { - throw new LowlevelError( - "CALLOTHER: Count Leading Ones op only supports varnodes of size 8-bytes or less"); - } - - MemoryState memoryState = emu.getMemoryState(); - - long value = memoryState.getValue(in); - long mask = 1L << ((in.getSize() * 8) - 1); - long count = 0; - while ( (mask & value) != 0 ) { - ++count; - value = value << 1; - } - - memoryState.setValue(out, count); - } -} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/emulate/callother/CountLeadingZerosOpBehavior.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/emulate/callother/CountLeadingZerosOpBehavior.java deleted file mode 100644 index b65ee6b276..0000000000 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/emulate/callother/CountLeadingZerosOpBehavior.java +++ /dev/null @@ -1,60 +0,0 @@ -/* ### - * IP: GHIDRA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.pcode.emulate.callother; - -import ghidra.pcode.emulate.Emulate; -import ghidra.pcode.memstate.MemoryState; -import ghidra.pcodeCPort.error.LowlevelError; -import ghidra.program.model.pcode.Varnode; - -public class CountLeadingZerosOpBehavior implements OpBehaviorOther { - - @Override - public void evaluate(Emulate emu, Varnode out, Varnode[] inputs) { - - if (out == null) { - throw new LowlevelError("CALLOTHER: Count Leading Zeros op missing required output"); - } - - if (inputs.length != 2 || inputs[1].getSize() == 0 || inputs[1].isConstant()) { - throw new LowlevelError( - "CALLOTHER: Count Leading Zeros op requires one non-constant varnode input"); - } - - // TODO: add support for larger varnode sizes - - Varnode in = inputs[1]; - if (in.getSize() > 8 || out.getSize() > 8) { - throw new LowlevelError( - "CALLOTHER: Count Leading Zeros op only supports varnodes of size 8-bytes or less"); - } - - MemoryState memoryState = emu.getMemoryState(); - - long value = memoryState.getValue(in); - long mask = 1L << ((in.getSize() * 8) - 1); - long count = 0; - while (mask != 0) { - if ((mask & value) != 0) { - break; - } - ++count; - mask >>>= 1; - } - - memoryState.setValue(out, count); - } -} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/opbehavior/OpBehaviorFactory.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/opbehavior/OpBehaviorFactory.java index 3bb4794ada..c68028bf1b 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/opbehavior/OpBehaviorFactory.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/opbehavior/OpBehaviorFactory.java @@ -104,6 +104,7 @@ public class OpBehaviorFactory { opBehaviorMap.put(PcodeOp.INSERT, new SpecialOpBehavior(PcodeOp.INSERT)); opBehaviorMap.put(PcodeOp.EXTRACT, new SpecialOpBehavior(PcodeOp.EXTRACT)); opBehaviorMap.put(PcodeOp.POPCOUNT, new OpBehaviorPopcount()); + opBehaviorMap.put(PcodeOp.LZCOUNT, new OpBehaviorLzcount()); } private OpBehaviorFactory() { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/opbehavior/OpBehaviorLzcount.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/opbehavior/OpBehaviorLzcount.java new file mode 100644 index 0000000000..72d495df66 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/opbehavior/OpBehaviorLzcount.java @@ -0,0 +1,48 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.pcode.opbehavior; + +import java.math.BigInteger; + +import ghidra.program.model.pcode.PcodeOp; + +public class OpBehaviorLzcount extends UnaryOpBehavior { + + public OpBehaviorLzcount() { + super(PcodeOp.LZCOUNT); + } + + @Override + public long evaluateUnary(int sizeout, int sizein, long val) { + long mask = 1L << ((sizein * 8) - 1); + long count = 0; + while (mask != 0) { + if ((mask & val) != 0) { + break; + } + ++count; + mask >>>= 1; + } + + return count; + } + + @Override + public BigInteger evaluateUnary(int sizeout, int sizein, BigInteger unsignedIn1) { + // TODO Auto-generated method stub + return null; + } +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/opcodes/OpCode.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/opcodes/OpCode.java index 020ec96d66..4d91cca6b8 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/opcodes/OpCode.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/opcodes/OpCode.java @@ -113,6 +113,7 @@ public enum OpCode { CPUI_INSERT, CPUI_EXTRACT, CPUI_POPCOUNT, + CPUI_LZCOUNT, CPUI_MAX; @@ -203,7 +204,8 @@ public enum OpCode { "UNUSED1", "FLOAT_NAN", "FLOAT_ADD", "FLOAT_DIV", "FLOAT_MULT", "FLOAT_SUB", "FLOAT_NEG", "FLOAT_ABS", "FLOAT_SQRT", "INT2FLOAT", "FLOAT2FLOAT", "TRUNC", "CEIL", "FLOOR", "ROUND", "BUILD", "DELAY_SLOT", "PIECE", "SUBPIECE", "CAST", "LABEL", - "CROSSBUILD", "SEGMENTOP", "CPOOLREF", "NEW", "INSERT", "EXTRACT", "POPCOUNT" }; + "CROSSBUILD", "SEGMENTOP", "CPOOLREF", "NEW", "INSERT", "EXTRACT", "POPCOUNT", + "LZCOUNT" }; public static String get_opname(OpCode op) { return opcode_name[op.ordinal()]; @@ -212,7 +214,7 @@ public enum OpCode { static final int opcode_indices[] = { 0, 39, 37, 40, 38, 4, 6, 60, 7, 8, 9, 64, 5, 57, 1, 68, 66, 61, 71, 55, 52, 47, 48, 41, 43, 44, 49, 46, 51, 42, 53, 50, 58, 70, 54, 24, 19, 27, 21, 33, 11, 29, 15, 16, 32, 25, 12, 28, 35, 30, 23, 22, 34, 18, 13, 14, 36, 31, 20, 26, 17, - 65, 2, 69, 62, 72, 10, 59, 67, 3, 63, 56, 45 }; + 65, 2, 73, 69, 62, 72, 10, 59, 67, 3, 63, 56, 45 }; public static OpCode get_opcode(String nm) { // Use binary search to find name int min = 1; // Don't include BLANK diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slgh_compile/PcodeCompile.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slgh_compile/PcodeCompile.java index fa4b7a2d1c..112a531fa9 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slgh_compile/PcodeCompile.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slgh_compile/PcodeCompile.java @@ -996,6 +996,9 @@ public abstract class PcodeCompile { if ("popcount".equals(name) && hasOperands(1, operands, location, name)) { return createOp(location, OpCode.CPUI_POPCOUNT, r); } + if ("lzcount".equals(name) && hasOperands(1, operands, location, name)) { + return createOp(location, OpCode.CPUI_LZCOUNT, r); + } return null; } @@ -1073,6 +1076,9 @@ public abstract class PcodeCompile { if ("popcount".equals(name)) { return true; } + if ("lzcount".equals(name)) { + return true; + } return false; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/DynamicHash.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/DynamicHash.java index 17642fef21..54bfa6cf16 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/DynamicHash.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/DynamicHash.java @@ -75,7 +75,7 @@ public class DynamicHash { 0, // CAST is skipped PcodeOp.INT_ADD, PcodeOp.INT_ADD, // PTRADD and PTRSUB hash same as INT_ADD PcodeOp.SEGMENTOP, PcodeOp.CPOOLREF, PcodeOp.NEW, PcodeOp.INSERT, PcodeOp.EXTRACT, - PcodeOp.POPCOUNT }; + PcodeOp.POPCOUNT, PcodeOp.LZCOUNT }; /** * An edge between a Varnode and a PcodeOp diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeOp.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeOp.java index aa889a4fed..9918411433 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeOp.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeOp.java @@ -132,8 +132,9 @@ public class PcodeOp { public static final int INSERT = 70; public static final int EXTRACT = 71; public static final int POPCOUNT = 72; + public static final int LZCOUNT = 73; - public static final int PCODE_MAX = 73; + public static final int PCODE_MAX = 74; private static Hashtable opcodeTable; @@ -689,6 +690,8 @@ public class PcodeOp { return "EXTRACT"; case POPCOUNT: return "POPCOUNT"; + case LZCOUNT: + return "LZCOUNT"; default: return "INVALID_OP"; diff --git a/Ghidra/Processors/68000/data/languages/68000.pspec b/Ghidra/Processors/68000/data/languages/68000.pspec index 14df2cbd64..52e71d47e5 100644 --- a/Ghidra/Processors/68000/data/languages/68000.pspec +++ b/Ghidra/Processors/68000/data/languages/68000.pspec @@ -2,7 +2,6 @@ - diff --git a/Ghidra/Processors/68000/data/languages/68000.sinc b/Ghidra/Processors/68000/data/languages/68000.sinc index b6c736010f..e4d7d037b6 100644 --- a/Ghidra/Processors/68000/data/languages/68000.sinc +++ b/Ghidra/Processors/68000/data/languages/68000.sinc @@ -825,8 +825,6 @@ with : extGUARD=1 { logflags(); tmp:4 = e2l; getbitfield(tmp, f_off, f_wd); f_reg = tmp; resbitflags(f_reg, f_wd-1); } -define pcodeop countLeadingZeros; - :bfffo e2l{f_off:f_wd},f_reg is opbig=0xed & op67=3 & $(DAT_DIR_CTL_ADDR_MODES); f_off & f_wd & f_reg & flddo=0 & fldoffdat=0 & flddw=0 & fldwddat=0; e2l [ savmod2=savmod1; regtsan=regtfan; ] { # "Find First One in Bit Field" pronounced "boo-foe" @@ -839,7 +837,7 @@ define pcodeop countLeadingZeros; ZF = (tmp == 0); VF = 0; CF = 0; - tmp2:4 = countLeadingZeros(tmp); + tmp2:4 = lzcount(tmp); # NB- it seems the MSB left most bit is really at offset 0, # and the right LSB is at offset 31 tmp3:4 = tmp2 % 32:4; # need mod for when there are all zeros, when tmp2 would = 32 diff --git a/Ghidra/Processors/68000/src/main/java/ghidra/program/emulation/m68kEmulateInstructionStateModifier.java b/Ghidra/Processors/68000/src/main/java/ghidra/program/emulation/m68kEmulateInstructionStateModifier.java index 98a56cd986..e491c6ea66 100644 --- a/Ghidra/Processors/68000/src/main/java/ghidra/program/emulation/m68kEmulateInstructionStateModifier.java +++ b/Ghidra/Processors/68000/src/main/java/ghidra/program/emulation/m68kEmulateInstructionStateModifier.java @@ -17,7 +17,6 @@ package ghidra.program.emulation; import ghidra.pcode.emulate.Emulate; import ghidra.pcode.emulate.EmulateInstructionStateModifier; -import ghidra.pcode.emulate.callother.CountLeadingZerosOpBehavior; import ghidra.pcode.emulate.callother.OpBehaviorOther; import ghidra.pcode.memstate.MemoryState; import ghidra.pcodeCPort.error.LowlevelError; @@ -45,10 +44,6 @@ public class m68kEmulateInstructionStateModifier extends EmulateInstructionState ISA_MODE0 = new RegisterValue(isaModeReg, BigInteger.ZERO); */ - // These classes are defined here: - // ghidra/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/emulate/callother - - registerPcodeOpBehavior("countLeadingZeros", new CountLeadingZerosOpBehavior()); registerPcodeOpBehavior("findFirstOne", new FindFirstOneOpBehavior()); } diff --git a/Ghidra/Processors/ARM/data/languages/ARM.sinc b/Ghidra/Processors/ARM/data/languages/ARM.sinc index 5869bfe290..09f31819e5 100644 --- a/Ghidra/Processors/ARM/data/languages/ARM.sinc +++ b/Ghidra/Processors/ARM/data/languages/ARM.sinc @@ -117,7 +117,6 @@ define context contextreg ARMcondCk = (35,35) # Finished ARM condition check phase ; -define pcodeop count_leading_zeroes; define pcodeop coprocessor_function; define pcodeop coprocessor_function2; define pcodeop coprocessor_load; diff --git a/Ghidra/Processors/ARM/data/languages/ARMTHUMBinstructions.sinc b/Ghidra/Processors/ARM/data/languages/ARMTHUMBinstructions.sinc index c53819453d..18093dcf98 100644 --- a/Ghidra/Processors/ARM/data/languages/ARMTHUMBinstructions.sinc +++ b/Ghidra/Processors/ARM/data/languages/ARMTHUMBinstructions.sinc @@ -1608,7 +1608,7 @@ define pcodeop IndexCheck; :clz^ItCond Rd0811,Rm0003 is TMode=1 & ItCond & op4=0xfab & Rm0003; op12=15 & Rd0811 { build ItCond; - Rd0811 = count_leading_zeroes(Rm0003); + Rd0811 = lzcount(Rm0003); } :cmn^ItCond Rn0003,ThumbExpandImm12 is TMode=1 & ItCond & (op11=0x1e & thc0909=0 & sop0508=8 & thc0404=1 & Rn0003; thc1515=0 & thc0811=15) & ThumbExpandImm12 diff --git a/Ghidra/Processors/ARM/data/languages/ARMinstructions.sinc b/Ghidra/Processors/ARM/data/languages/ARMinstructions.sinc index 785f5a36f8..3a370d2338 100644 --- a/Ghidra/Processors/ARM/data/languages/ARMinstructions.sinc +++ b/Ghidra/Processors/ARM/data/languages/ARMinstructions.sinc @@ -2484,7 +2484,7 @@ ArmPCRelImmed12: reloff is U23=0 & immed & rotate { build COND; build rm; - Rd = count_leading_zeroes(rm); + Rd = lzcount(rm); } @endif # VERSION_5 diff --git a/Ghidra/Processors/ARM/src/main/java/ghidra/program/emulation/ARMEmulateInstructionStateModifier.java b/Ghidra/Processors/ARM/src/main/java/ghidra/program/emulation/ARMEmulateInstructionStateModifier.java index f5ce6859d7..eaeb514c90 100644 --- a/Ghidra/Processors/ARM/src/main/java/ghidra/program/emulation/ARMEmulateInstructionStateModifier.java +++ b/Ghidra/Processors/ARM/src/main/java/ghidra/program/emulation/ARMEmulateInstructionStateModifier.java @@ -19,7 +19,6 @@ import java.math.BigInteger; import ghidra.pcode.emulate.Emulate; import ghidra.pcode.emulate.EmulateInstructionStateModifier; -import ghidra.pcode.emulate.callother.CountLeadingZerosOpBehavior; import ghidra.pcode.error.LowlevelError; import ghidra.program.model.address.Address; import ghidra.program.model.lang.Register; @@ -46,8 +45,6 @@ public class ARMEmulateInstructionStateModifier extends EmulateInstructionStateM aMode = new RegisterValue(TModeReg, BigInteger.ZERO); } - registerPcodeOpBehavior("count_leading_zeroes", new CountLeadingZerosOpBehavior()); - /** * We could registerPcodeOpBehavior for one or more of the following pcodeop's: * @@ -85,7 +82,6 @@ public class ARMEmulateInstructionStateModifier extends EmulateInstructionStateM coprocessor_store2 coprocessor_storelong coprocessor_storelong2 - count_leading_zeroes disableDataAbortInterrupts disableFIQinterrupts disableIRQinterrupts diff --git a/Ghidra/Processors/MIPS/data/languages/mips.sinc b/Ghidra/Processors/MIPS/data/languages/mips.sinc index 6d80485cf7..a2660f785d 100755 --- a/Ghidra/Processors/MIPS/data/languages/mips.sinc +++ b/Ghidra/Processors/MIPS/data/languages/mips.sinc @@ -1001,12 +1001,6 @@ define pcodeop getCopRegH; define pcodeop setCopReg; define pcodeop setCopRegH; -# countLeadingOnes(val) -define pcodeop countLeadingOnes; - -# countLeadingZeros(val) -define pcodeop countLeadingZeros; - # extractField(value, msbd, lsb) define pcodeop extractField; diff --git a/Ghidra/Processors/MIPS/data/languages/mips32Instructions.sinc b/Ghidra/Processors/MIPS/data/languages/mips32Instructions.sinc index d2b91afd67..a7bc95af1c 100644 --- a/Ghidra/Processors/MIPS/data/languages/mips32Instructions.sinc +++ b/Ghidra/Processors/MIPS/data/languages/mips32Instructions.sinc @@ -980,13 +980,13 @@ define pcodeop SYNC; # 0111 00ss ssst tttt dddd d000 0010 0001 :clo RD, RSsrc is $(AMODE) & REL6=0 & prime=0x1C & sa=0x0 & fct=0x21 & RD & RSsrc { # Count leading ones in a word - RD = countLeadingOnes( RSsrc ); + RD = lzcount( ~RSsrc ); } # 0111 00ss ssst tttt dddd d000 0010 0000 :clz RD, RSsrc is $(AMODE) & REL6=0 & prime=0x1C & sa=0x0 & fct=0x20 & RD & RSsrc { # Count leading zeros in a word - RD = countLeadingZeros( RSsrc ); + RD = lzcount( RSsrc ); } # 0000 00ss ssst tttt 0000 0000 0001 1010 @@ -1573,11 +1573,11 @@ define pcodeop SYNC; } :clo RD, RSsrc is $(AMODE) & REL6=1 & prime=0x00 & op=0 & sa=0x1 & fct=0x11 & RD & RSsrc { - RD = countLeadingOnes( RSsrc ); + RD = lzcount( ~RSsrc ); } :clz RD, RSsrc is $(AMODE) & REL6=1 & prime=0x00 & op=0 & sa=0x1 & fct=0x10 & RD & RSsrc { - RD = countLeadingZeros( RSsrc ); + RD = lzcount( RSsrc ); } :div RD, RS32src, RT32src is $(AMODE) & REL6=1 & prime=0x00 & fct=0x1A & fct2=0x02 & RD & RS32src & RT32src { diff --git a/Ghidra/Processors/MIPS/data/languages/mips64Instructions.sinc b/Ghidra/Processors/MIPS/data/languages/mips64Instructions.sinc index 3c09b0b428..786cd32907 100644 --- a/Ghidra/Processors/MIPS/data/languages/mips64Instructions.sinc +++ b/Ghidra/Processors/MIPS/data/languages/mips64Instructions.sinc @@ -7,11 +7,11 @@ # 0111 00ss ssst tttt dddd d000 0010 0101 :dclo RD, RSsrc is $(AMODE) & ((REL6=0 & prime=0x1C & sa=0x0 & fct=0x25) | (REL6=1 & prime=0x00 & sa=0x1 & fct=0x13 & op=0)) & RD & RSsrc { - RD = countLeadingOnes( RSsrc ); + RD = lzcount( ~RSsrc ); } # 0111 00ss ssst tttt dddd d000 0010 0100 :dclz RD, RSsrc is $(AMODE) & ((REL6=0 & prime=0x1C & sa=0x0 & fct=0x24) | (REL6=1 & prime=0x00 & sa=0x1 & fct=0x12 & op=0)) & RD & RSsrc { - RD = countLeadingZeros( RSsrc ); + RD = lzcount( RSsrc ); } # 0111 11ss ssst tttt mmmm mLLL LL00 0011 diff --git a/Ghidra/Processors/MIPS/data/languages/mipsmicro.sinc b/Ghidra/Processors/MIPS/data/languages/mipsmicro.sinc index 23870b9511..f9fc0d9947 100644 --- a/Ghidra/Processors/MIPS/data/languages/mipsmicro.sinc +++ b/Ghidra/Processors/MIPS/data/languages/mipsmicro.sinc @@ -697,11 +697,11 @@ STORE_TOP16: STORE_SREG^ra,EXT_CODE4E(sp) is mic_listr6 & REL6=1 & STORE_SREG & } :clo mic_rt32_5, RS0L is ISA_MODE=1 & RELP=0 & mic_op=0b000000 & mic_rt32_5 & RS0L ; micb_poolax=0b111100 & micb_axf=0b0100101100 { - mic_rt32_5 = countLeadingOnes( RS0L ); + mic_rt32_5 = lzcount( ~RS0L ); } :clz mic_rt32_5, RS0L is ISA_MODE=1 & RELP=0 & mic_op=0b000000 & mic_rt32_5 & RS0L ; micb_poolax=0b111100 & micb_axf=0b0101101100 { - mic_rt32_5 = countLeadingZeros( RS0L ); + mic_rt32_5 = lzcount( RS0L ); } :cop2 EXT_MU23 is ISA_MODE=1 & RELP=0 & mic_op=0b000000 & mic_code ; micb_cop=0b010 & EXT_MU23 [ ext_32_code=mic_code; ] { @@ -1676,11 +1676,11 @@ STORE_TOP16: STORE_SREG^ra,EXT_CODE4E(sp) is mic_listr6 & REL6=1 & STORE_SREG & } :dclo mic_rt32_5, mic_rs32_0 is ISA_MODE=1 & RELP=0 & mic_op=0b010110 & mic_rt32_5 & mic_rs32_0 ; micb_poolax=0b111100 & micb_axf=0b0100101100 { - mic_rt32_5 = countLeadingOnes( mic_rs32_0 ); + mic_rt32_5 = lzcount( ~mic_rs32_0 ); } :dclz mic_rt32_5, mic_rs32_0 is ISA_MODE=1 & RELP=0 & mic_op=0b010110 & mic_rt32_5 & mic_rs32_0 ; micb_poolax=0b111100 & micb_axf=0b0101101100 { - mic_rt32_5 = countLeadingZeros( mic_rs32_0 ); + mic_rt32_5 = lzcount( mic_rs32_0 ); } :dext mic_rt32_5, mic_rs32_0, micb_pos, SIZEP is ISA_MODE=1 & RELP=0 & mic_op=0b010110 & REL6=1 & mic_rt32_5 & mic_rs32_0 ; micb_poolax=0b101100 & micb_pos & SIZEP { diff --git a/Ghidra/Processors/MIPS/src/main/java/ghidra/program/emulation/MIPSEmulateInstructionStateModifier.java b/Ghidra/Processors/MIPS/src/main/java/ghidra/program/emulation/MIPSEmulateInstructionStateModifier.java index a47332f564..374838074c 100644 --- a/Ghidra/Processors/MIPS/src/main/java/ghidra/program/emulation/MIPSEmulateInstructionStateModifier.java +++ b/Ghidra/Processors/MIPS/src/main/java/ghidra/program/emulation/MIPSEmulateInstructionStateModifier.java @@ -19,8 +19,6 @@ import java.math.BigInteger; import ghidra.pcode.emulate.Emulate; import ghidra.pcode.emulate.EmulateInstructionStateModifier; -import ghidra.pcode.emulate.callother.CountLeadingOnesOpBehavior; -import ghidra.pcode.emulate.callother.CountLeadingZerosOpBehavior; import ghidra.pcode.error.LowlevelError; import ghidra.program.model.address.Address; import ghidra.program.model.lang.Register; @@ -49,13 +47,6 @@ public class MIPSEmulateInstructionStateModifier extends EmulateInstructionState ISA_MODE0 = new RegisterValue(isaModeReg, BigInteger.ZERO); } - // These classes are defined here: - // ghidra/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/emulate/callother - - registerPcodeOpBehavior("countLeadingZeros", new CountLeadingZerosOpBehavior()); - - registerPcodeOpBehavior("countLeadingOnes", new CountLeadingOnesOpBehavior()); - /** * We could registerPcodeOpBehavior for one or more of the following * pcodeop's: diff --git a/Ghidra/Processors/PowerPC/data/languages/ppc_common.sinc b/Ghidra/Processors/PowerPC/data/languages/ppc_common.sinc index 8498e4bdce..aaa76cc4ac 100644 --- a/Ghidra/Processors/PowerPC/data/languages/ppc_common.sinc +++ b/Ghidra/Processors/PowerPC/data/languages/ppc_common.sinc @@ -1415,7 +1415,6 @@ attach variables vrC_8_15 [vr0_8_15 vr1_8_15 vr2_8_15 vr3_8_15 vr4_8_15 vr5_8_15 ################################################################ define pcodeop clearHistory; -define pcodeop countLeadingZeros; define pcodeop countTrailingZeros; define pcodeop dataCacheBlockAllocate; define pcodeop dataCacheBlockFlush; diff --git a/Ghidra/Processors/PowerPC/data/languages/ppc_instructions.sinc b/Ghidra/Processors/PowerPC/data/languages/ppc_instructions.sinc index 1f6372f9bc..b9ca56c0ff 100644 --- a/Ghidra/Processors/PowerPC/data/languages/ppc_instructions.sinc +++ b/Ghidra/Processors/PowerPC/data/languages/ppc_instructions.sinc @@ -814,13 +814,13 @@ #cntlzd r0,r0 0x7c 00 00 74 :cntlzd A,S is OP=31 & S & A & BITS_11_15=0 & XOP_1_10=58 & Rc=0 { - A = countLeadingZeros(S); + A = lzcount(S); } #cntlzd. r0,r0 0x7c 00 00 75 :cntlzd. A,S is OP=31 & S & A & BITS_11_15=0 & XOP_1_10=58 & Rc=1 { - A = countLeadingZeros(S); + A = lzcount(S); cr0flags(A); } @endif @@ -828,13 +828,13 @@ #cntlzw r0,r0 0x7c 00 00 34 :cntlzw A,S is OP=31 & S & A & BITS_11_15=0 & XOP_1_10=26 & Rc=0 { - A = countLeadingZeros(S:4); + A = lzcount(S:4); } #cntlzw. r0,r0 0x7c 00 00 35 :cntlzw. A,S is OP=31 & S & A & BITS_11_15=0 & XOP_1_10=26 & Rc=1 { - A = countLeadingZeros(S:4); + A = lzcount(S:4); cr0flags(A); } #=========================================================== diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/program/emulation/PPCEmulateInstructionStateModifier.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/program/emulation/PPCEmulateInstructionStateModifier.java index 4b6a7a3cc3..1e44af9bdb 100644 --- a/Ghidra/Processors/PowerPC/src/main/java/ghidra/program/emulation/PPCEmulateInstructionStateModifier.java +++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/program/emulation/PPCEmulateInstructionStateModifier.java @@ -19,7 +19,6 @@ import java.math.BigInteger; import ghidra.pcode.emulate.Emulate; import ghidra.pcode.emulate.EmulateInstructionStateModifier; -import ghidra.pcode.emulate.callother.CountLeadingZerosOpBehavior; import ghidra.pcode.emulate.callother.OpBehaviorOther; import ghidra.pcode.memstate.MemoryState; import ghidra.pcodeCPort.error.LowlevelError; @@ -30,7 +29,6 @@ public class PPCEmulateInstructionStateModifier extends EmulateInstructionStateM public PPCEmulateInstructionStateModifier(Emulate emu) { super(emu); - registerPcodeOpBehavior("countLeadingZeros", new CountLeadingZerosOpBehavior()); registerPcodeOpBehavior("vectorPermute", new vectorPermuteOpBehavior()); } diff --git a/Ghidra/Processors/tricore/data/languages/tricore.sinc b/Ghidra/Processors/tricore/data/languages/tricore.sinc index 992bc437e3..1c20278230 100644 --- a/Ghidra/Processors/tricore/data/languages/tricore.sinc +++ b/Ghidra/Processors/tricore/data/languages/tricore.sinc @@ -490,8 +490,6 @@ define pcodeop cache_index_ivld; define pcodeop cache_index_wb; define pcodeop cache_index_wi; define pcodeop round16; -define pcodeop leading_ones; -define pcodeop leading_zeros; define pcodeop leading_signs; define pcodeop crc32; @@ -1840,7 +1838,7 @@ SC: [a10]const0815Z10zz is PCPMode=0 & a10 & const0815Z10zz & op0003=8 & op0404= # CLO D[c], D[a] (RR) :clo Rd2831,Rd0811 is PCPMode=0 & Rd0811 & op0007=0xf & op1215=0x0 ; Rd2831 & op1627=0x1c0 { - Rd2831 = leading_ones(Rd0811); + Rd2831 = lzcount(~Rd0811); } # CLO.H D[c], D[a] (RR) @@ -1848,8 +1846,8 @@ SC: [a10]const0815Z10zz is PCPMode=0 & a10 & const0815Z10zz & op0003=8 & op0404= { local tmp1:4 = zext(Rd0811[16,16]); local tmp0:4 = zext(Rd0811[0,16]); - Rd2831[16,16] = leading_ones(tmp1); - Rd2831[0,16] = leading_ones(tmp0); + Rd2831[16,16] = lzcount(~tmp1); + Rd2831[0,16] = lzcount(~tmp0); } # CLS D[c], D[a] (RR) @@ -1870,13 +1868,13 @@ SC: [a10]const0815Z10zz is PCPMode=0 & a10 & const0815Z10zz & op0003=8 & op0404= # CLZ D[c], D[a] (RR) :clz Rd2831,Rd0811 is PCPMode=0 & Rd0811 & op0007=0xf & op1215=0x0 ; Rd2831 & op1627=0x1b0 { - Rd2831 = leading_zeros(Rd0811); + Rd2831 = lzcount(Rd0811); } # CLZ.H D[c], D[a] (RR) :clz.h Rd2831,Rd0811 is PCPMode=0 & Rd0811 & op0007=0xf & op1215=0x0 ; Rd2831 & op1627=0x7c0 { - local result:4 = (leading_zeros(Rd0811[16,16]) << 16) | leading_zeros(Rd0811[0,16]); + local result:4 = (lzcount(Rd0811[16,16]) << 16) | lzcount(Rd0811[0,16]); Rd2831 = result; } diff --git a/Ghidra/Processors/x86/data/languages/lzcnt.sinc b/Ghidra/Processors/x86/data/languages/lzcnt.sinc index be3861b875..6927814bb9 100644 --- a/Ghidra/Processors/x86/data/languages/lzcnt.sinc +++ b/Ghidra/Processors/x86/data/languages/lzcnt.sinc @@ -11,57 +11,22 @@ macro lzcntflags(input, output) { :LZCNT Reg16, rm16 is vexMode=0 & opsize=0 & $(PRE_66) & $(PRE_F3) & byte=0x0F; byte=0xBD; Reg16 ... & rm16 { - countTmp:2 = 0; - inputTmp:2 = rm16; - - - if ((inputTmp & 0x8000) != 0) goto ; - - countTmp = countTmp + 1; - inputTmp = (inputTmp << 1) | 1; - goto ; - - - lzcntflags(rm16, countTmp); - Reg16 = countTmp; - + Reg16 = lzcount(rm16); + lzcntflags(rm16, Reg16); } :LZCNT Reg32, rm32 is vexMode=0 & opsize=1 & $(PRE_F3) & byte=0x0F; byte=0xBD; Reg32 ... & check_Reg32_dest ... & rm32 { - countTmp:4 = 0; - inputTmp:4 = rm32; - - - if ((inputTmp & 0x80000000) != 0) goto ; - - countTmp = countTmp + 1; - inputTmp = (inputTmp << 1) | 1; - goto ; - - - lzcntflags(rm32, countTmp); - Reg32 = countTmp; + Reg32 = lzcount(rm32); + lzcntflags(rm32, Reg32); build check_Reg32_dest; } @ifdef IA64 :LZCNT Reg64, rm64 is $(LONGMODE_ON) & vexMode=0 & opsize=2 & $(PRE_F3) & $(REX_W) & byte=0x0F; byte=0xBD; Reg64 ... & rm64 { - countTmp:8 = 0; - inputTmp:8 = rm64; - - - if ((inputTmp & 0x8000000000000000) != 0) goto ; - - countTmp = countTmp + 1; - inputTmp = (inputTmp << 1) | 1; - goto ; - - - lzcntflags(rm64, countTmp); - Reg64 = countTmp; - + Reg64 = lzcount(rm64); + lzcntflags(rm64, Reg64); } @endif diff --git a/GhidraBuild/EclipsePlugins/GhidraSleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/Sleigh.xtext b/GhidraBuild/EclipsePlugins/GhidraSleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/Sleigh.xtext index ed7bf29e7f..ec107edb0b 100644 --- a/GhidraBuild/EclipsePlugins/GhidraSleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/Sleigh.xtext +++ b/GhidraBuild/EclipsePlugins/GhidraSleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/Sleigh.xtext @@ -661,6 +661,7 @@ exprSingle returns Expression: | pcodeop='floor' '(' op1=expr ')' | pcodeop='round' '(' op1=expr ')' | pcodeop='popcount' '(' op1=expr ')' + | pcodeop='lzcount' '(' op1=expr ')' | pcodeop='cpool' '(' op1=expr ',' op2=expr ',' op3=expr ')' | pcodeop='newobject' '(' op1=newObjParams ')' | op=[macroOrPcode] op1=paramlist @@ -1142,4 +1143,4 @@ terminal WS : (' '|'\t'|'\r'|'\n')+; // //terminal DEFINENAME: 'synthetic:DEFINENAME'; //terminal BEGINDEFINE: 'synthetic:BEGINDEFINE'; -//terminal ENDDEFINE: 'synthetic:ENDDEFINE'; \ No newline at end of file +//terminal ENDDEFINE: 'synthetic:ENDDEFINE'; diff --git a/GhidraDocs/languages/html/pcodedescription.html b/GhidraDocs/languages/html/pcodedescription.html index 368b4c2178..547ed595b2 100644 --- a/GhidraDocs/languages/html/pcodedescription.html +++ b/GhidraDocs/languages/html/pcodedescription.html @@ -676,6 +676,49 @@ count is zero extended into the output varnode.

+LZCOUNT

+
+
popcount(v0) Count 1 bits in v0.
LZCOUNTlzcount(v0)Counts the number of leading zero bits in v0.
INT_EQUAL v0 == v1
LogicalINT_NEGATE, INT_XOR, INT_AND, INT_OR, INT_LEFT, INT_RIGHT, INT_SRIGHT, POPCOUNTINT_NEGATE, INT_XOR, INT_AND, INT_OR, INT_LEFT, INT_RIGHT, INT_SRIGHT, + POPCOUNT, LZCOUNT
Integer ComparisonCount the number of 1 bits in v0.
LZCOUNTlzcount(v0)Count the number of leading 0 bits in v0. +
(simulated) v0[6,1]
++++ + + + + + + + + + + + + + + + + + + + + + + + + + +
ParametersDescription
input0Input varnode to count.
outputResulting integer varnode containing count.
Semantic statement
output = lzcount(input0);
+ +

+This operator counts the number of zeros starting at the most significant bit. +For instance, for a 4-byte varnode, a value of 0 returns 32, a value of 1 +returns 31, and the value 231 returns 0. +The resulting count is zero extended into the output varnode. +

+ +
+

INT_EQUAL

diff --git a/GhidraDocs/languages/html/pcoderef.html b/GhidraDocs/languages/html/pcoderef.html index 255621d35b..8ac9d5d818 100644 --- a/GhidraDocs/languages/html/pcoderef.html +++ b/GhidraDocs/languages/html/pcoderef.html @@ -26,7 +26,7 @@

P-Code Reference Manual

-

Last updated September 5, 2019

+

Last updated March 2, 2023


@@ -117,52 +117,58 @@ - + - + - + - + - + - + - + - + + + + + + +
INT_EQUALLZCOUNT INT_MULT FLOAT_FLOOR
INT_NOTEQUALINT_EQUAL INT_DIV FLOAT_ROUND
INT_LESSINT_NOTEQUAL INT_REM FLOAT_NAN
INT_SLESSINT_LESS INT_SDIV INT2FLOAT
INT_LESSEQUALINT_SLESS INT_SREM FLOAT2FLOAT
INT_SLESSEQUALINT_LESSEQUAL BOOL_NEGATE TRUNC
INT_ZEXTINT_SLESSEQUAL BOOL_XOR CPOOLREF
INT_SEXTINT_ZEXT BOOL_AND NEW
INT_SEXT
diff --git a/GhidraDocs/languages/html/reference.html b/GhidraDocs/languages/html/reference.html index 9b694c1549..2fde8b5163 100644 --- a/GhidraDocs/languages/html/reference.html +++ b/GhidraDocs/languages/html/reference.html @@ -139,6 +139,11 @@ popcount(v0) Count 1 bits in v0. + + LZCOUNT + lzcount(v0) + Counts the number of leading zero bits in v0. + INT_EQUAL v0 == v1 diff --git a/GhidraDocs/languages/html/sleigh.html b/GhidraDocs/languages/html/sleigh.html index aede7a2eb4..e0468a4b26 100644 --- a/GhidraDocs/languages/html/sleigh.html +++ b/GhidraDocs/languages/html/sleigh.html @@ -27,7 +27,7 @@

SLEIGH

A Language for Rapid Processor Specification

-

Last updated August 24, 2022

+

Last updated March 2, 2023

Originally published December 16, 2005


@@ -372,7 +372,8 @@ general purpose processor instruction sets. They break up into groups. Logical - INT_NEGATE, INT_XOR, INT_AND, INT_OR, INT_LEFT, INT_RIGHT, INT_SRIGHT, POPCOUNT + INT_NEGATE, INT_XOR, INT_AND, INT_OR, INT_LEFT, INT_RIGHT, INT_SRIGHT, + POPCOUNT, LZCOUNT Integer Comparison diff --git a/GhidraDocs/languages/html/sleigh_ref.html b/GhidraDocs/languages/html/sleigh_ref.html index 4914495b49..10210aaa57 100644 --- a/GhidraDocs/languages/html/sleigh_ref.html +++ b/GhidraDocs/languages/html/sleigh_ref.html @@ -83,6 +83,12 @@ to lowest. Count the number of 1 bits in v0. + + LZCOUNT + lzcount(v0) + Count the number of leading 0 bits in v0. + + (simulated) v0[6,1]