mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-10 06:02:09 +00:00
Create and use LZCOUNT Pcode op
This commit is contained in:
parent
865cd22cab
commit
14880b53c4
@ -3617,6 +3617,7 @@ void ActionDeadCode::propagateConsumed(vector<Varnode *> &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
|
||||
|
@ -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
|
||||
|
||||
};
|
||||
|
||||
|
@ -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();
|
||||
|
@ -102,6 +102,7 @@ void OpBehavior::registerInstructions(vector<OpBehavior *> &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));
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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; }
|
||||
|
@ -641,6 +641,7 @@ with { BEGIN(pattern); withsection = 1; slgh->calcContextLayout(); return WITH
|
||||
<sem>cpool { return OP_CPOOLREF; }
|
||||
<sem>newobject { return OP_NEW; }
|
||||
<sem>popcount { return OP_POPCOUNT; }
|
||||
<sem>lzcount { return OP_LZCOUNT; }
|
||||
<sem>if { return IF_KEY; }
|
||||
<sem>goto { return GOTO_KEY; }
|
||||
<sem>call { return CALL_KEY; }
|
||||
|
@ -102,6 +102,7 @@ void TypeOp::registerInstructions(vector<TypeOp *> &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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -2,7 +2,7 @@
|
||||
<article id="pcoderef_title">
|
||||
<info>
|
||||
<title>P-Code Reference Manual</title>
|
||||
<releaseinfo>Last updated September 5, 2019</releaseinfo>
|
||||
<releaseinfo>Last updated March 2, 2023</releaseinfo>
|
||||
</info>
|
||||
<table xml:id="mytoc.htmltable" width="90%" frame='none'>
|
||||
<col width="25%"/>
|
||||
@ -22,7 +22,7 @@
|
||||
<td><link linkend="cpui_int_sub">INT_SUB</link></td>
|
||||
<td><link linkend="cpui_float_equal">FLOAT_EQUAL</link></td>
|
||||
</tr>
|
||||
<tr>P
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><link linkend="cpui_store">STORE</link></td>
|
||||
<td><link linkend="cpui_int_carry">INT_CARRY</link></td>
|
||||
@ -90,52 +90,58 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><link linkend="cpui_int_equal">INT_EQUAL</link></td>
|
||||
<td><link linkend="cpui_lzcount">LZCOUNT</link></td>
|
||||
<td><link linkend="cpui_int_mult">INT_MULT</link></td>
|
||||
<td><link linkend="cpui_float_floor">FLOAT_FLOOR</link></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><link linkend="cpui_int_notequal">INT_NOTEQUAL</link></td>
|
||||
<td><link linkend="cpui_int_equal">INT_EQUAL</link></td>
|
||||
<td><link linkend="cpui_int_div">INT_DIV</link></td>
|
||||
<td><link linkend="cpui_float_round">FLOAT_ROUND</link></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><link linkend="cpui_int_less">INT_LESS</link></td>
|
||||
<td><link linkend="cpui_int_notequal">INT_NOTEQUAL</link></td>
|
||||
<td><link linkend="cpui_int_rem">INT_REM</link></td>
|
||||
<td><link linkend="cpui_float_nan">FLOAT_NAN</link></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><link linkend="cpui_int_sless">INT_SLESS</link></td>
|
||||
<td><link linkend="cpui_int_less">INT_LESS</link></td>
|
||||
<td><link linkend="cpui_int_sdiv">INT_SDIV</link></td>
|
||||
<td><link linkend="cpui_int2float">INT2FLOAT</link></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><link linkend="cpui_int_lessequal">INT_LESSEQUAL</link></td>
|
||||
<td><link linkend="cpui_int_sless">INT_SLESS</link></td>
|
||||
<td><link linkend="cpui_int_srem">INT_SREM</link></td>
|
||||
<td><link linkend="cpui_float2float">FLOAT2FLOAT</link></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><link linkend="cpui_int_slessequal">INT_SLESSEQUAL</link></td>
|
||||
<td><link linkend="cpui_int_lessequal">INT_LESSEQUAL</link></td>
|
||||
<td><link linkend="cpui_bool_negate">BOOL_NEGATE</link></td>
|
||||
<td><link linkend="cpui_trunc">TRUNC</link></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><link linkend="cpui_int_zext">INT_ZEXT</link></td>
|
||||
<td><link linkend="cpui_int_slessequal">INT_SLESSEQUAL</link></td>
|
||||
<td><link linkend="cpui_bool_xor">BOOL_XOR</link></td>
|
||||
<td><link linkend="cpui_cpoolref">CPOOLREF</link></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><link linkend="cpui_int_sext">INT_SEXT</link></td>
|
||||
<td><link linkend="cpui_int_zext">INT_ZEXT</link></td>
|
||||
<td><link linkend="cpui_bool_and">BOOL_AND</link></td>
|
||||
<td><link linkend="cpui_new">NEW</link></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><link linkend="cpui_int_sext">INT_SEXT</link></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<sect1 id="index">
|
||||
@ -977,6 +983,50 @@ count is zero extended into the output varnode.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="cpui_lzcount"><title>LZCOUNT</title>
|
||||
<informalexample>
|
||||
<table xml:id="lzcount.htmltable" frame="above" width="80%" rules="groups">
|
||||
<col width="23%"/>
|
||||
<col width="15%"/>
|
||||
<col width="61%"/>
|
||||
<thead>
|
||||
<tr>
|
||||
<td align="center" colspan="2"><emphasis role="bold">Parameters</emphasis></td>
|
||||
<td><emphasis role="bold">Description</emphasis></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align='right'>input0</td>
|
||||
<td/>
|
||||
<td>Input varnode to count.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align='right'>output</td>
|
||||
<td/>
|
||||
<td>Resulting integer varnode containing count.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td align="center" colspan="2"><emphasis role="bold">Semantic statement</emphasis></td>
|
||||
<td/>
|
||||
</tr>
|
||||
<tr>
|
||||
<td/>
|
||||
<td colspan="2"><code>output = lzcount(input0);</code></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</informalexample>
|
||||
<para>
|
||||
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 2<superscript>31</superscript> returns 0.
|
||||
The resulting count is zero extended into the output varnode.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="cpui_int_equal"><title>INT_EQUAL</title>
|
||||
<informalexample>
|
||||
<table xml:id="intequal.htmltable" frame="above" width="80%" rules="groups">
|
||||
@ -4058,6 +4108,11 @@ to SLEIGH <emphasis role="bold">bitrange</emphasis> syntax such as output = inpu
|
||||
<td><code>popcount(v0)</code></td>
|
||||
<td>Count 1 bits in v0.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>LZCOUNT</td>
|
||||
<td><code>lzcount(v0)</code></td>
|
||||
<td>Counts the number of leading zero bits in v0.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>INT_EQUAL</td>
|
||||
<td><code>v0 == v1</code></td>
|
||||
|
@ -4,7 +4,7 @@
|
||||
<title>SLEIGH</title>
|
||||
<subtitle>A Language for Rapid Processor Specification</subtitle>
|
||||
<pubdate>Originally published December 16, 2005</pubdate>
|
||||
<releaseinfo>Last updated August 24, 2022</releaseinfo>
|
||||
<releaseinfo>Last updated March 2, 2023</releaseinfo>
|
||||
</info>
|
||||
<simplesect id="sleigh_history">
|
||||
<info>
|
||||
@ -279,7 +279,8 @@ general purpose processor instruction sets. They break up into groups.
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Logical</td>
|
||||
<td><code>INT_NEGATE, INT_XOR, INT_AND, INT_OR, INT_LEFT, INT_RIGHT, INT_SRIGHT, POPCOUNT</code></td>
|
||||
<td><code>INT_NEGATE, INT_XOR, INT_AND, INT_OR, INT_LEFT, INT_RIGHT, INT_SRIGHT,
|
||||
POPCOUNT, LZCOUNT</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Integer Comparison</td>
|
||||
@ -3856,6 +3857,12 @@ to lowest.
|
||||
<td>Count the number of 1 bits in v0.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>LZCOUNT</code></td>
|
||||
<td><code>lzcount(v0)</code></td>
|
||||
<td>Count the number of leading 0 bits in v0.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>(simulated)</code></td>
|
||||
<td><code>v0[6,1]</code></td>
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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() {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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<String, Integer> opcodeTable;
|
||||
|
||||
@ -689,6 +690,8 @@ public class PcodeOp {
|
||||
return "EXTRACT";
|
||||
case POPCOUNT:
|
||||
return "POPCOUNT";
|
||||
case LZCOUNT:
|
||||
return "LZCOUNT";
|
||||
|
||||
default:
|
||||
return "INVALID_OP";
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
<processor_spec>
|
||||
<properties>
|
||||
<property key="emulateInstructionStateModifierClass" value="ghidra.program.emulation.m68kEmulateInstructionStateModifier"/>
|
||||
<property key="assemblyRating:68000:BE:32:default" value="PLATINUM"/>
|
||||
</properties>
|
||||
<programcounter register="PC"/>
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
#===========================================================
|
||||
|
@ -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());
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
<loopbegin>
|
||||
if ((inputTmp & 0x8000) != 0) goto <loopend>;
|
||||
|
||||
countTmp = countTmp + 1;
|
||||
inputTmp = (inputTmp << 1) | 1;
|
||||
goto <loopbegin>;
|
||||
|
||||
<loopend>
|
||||
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;
|
||||
|
||||
<loopbegin>
|
||||
if ((inputTmp & 0x80000000) != 0) goto <loopend>;
|
||||
|
||||
countTmp = countTmp + 1;
|
||||
inputTmp = (inputTmp << 1) | 1;
|
||||
goto <loopbegin>;
|
||||
|
||||
<loopend>
|
||||
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;
|
||||
|
||||
<loopbegin>
|
||||
if ((inputTmp & 0x8000000000000000) != 0) goto <loopend>;
|
||||
|
||||
countTmp = countTmp + 1;
|
||||
inputTmp = (inputTmp << 1) | 1;
|
||||
goto <loopbegin>;
|
||||
|
||||
<loopend>
|
||||
lzcntflags(rm64, countTmp);
|
||||
Reg64 = countTmp;
|
||||
|
||||
Reg64 = lzcount(rm64);
|
||||
lzcntflags(rm64, Reg64);
|
||||
}
|
||||
@endif
|
||||
|
||||
|
@ -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';
|
||||
//terminal ENDDEFINE: 'synthetic:ENDDEFINE';
|
||||
|
@ -676,6 +676,49 @@ count is zero extended into the output varnode.
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<div class="titlepage"><div><div><h3 class="title">
|
||||
<a name="cpui_lzcount"></a>LZCOUNT</h3></div></div></div>
|
||||
<div class="informalexample"><div class="table">
|
||||
<a name="lzcount.htmltable"></a><table xml:id="lzcount.htmltable" frame="above" width="80%" rules="groups">
|
||||
<col width="23%">
|
||||
<col width="15%">
|
||||
<col width="61%">
|
||||
<thead><tr>
|
||||
<td align="center" colspan="2"><span class="bold"><strong>Parameters</strong></span></td>
|
||||
<td><span class="bold"><strong>Description</strong></span></td>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="right">input0</td>
|
||||
<td></td>
|
||||
<td>Input varnode to count.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right">output</td>
|
||||
<td></td>
|
||||
<td>Resulting integer varnode containing count.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td align="center" colspan="2"><span class="bold"><strong>Semantic statement</strong></span></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td colspan="2"><code class="code">output = lzcount(input0);</code></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div></div>
|
||||
<p>
|
||||
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 2<sup>31</sup> returns 0.
|
||||
The resulting count is zero extended into the output varnode.
|
||||
</p>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<div class="titlepage"><div><div><h3 class="title">
|
||||
<a name="cpui_int_equal"></a>INT_EQUAL</h3></div></div></div>
|
||||
<div class="informalexample"><div class="table">
|
||||
<a name="intequal.htmltable"></a><table xml:id="intequal.htmltable" frame="above" width="80%" rules="groups">
|
||||
|
@ -26,7 +26,7 @@
|
||||
<div>
|
||||
<div><h1 class="title">
|
||||
<a name="pcoderef_title"></a>P-Code Reference Manual</h1></div>
|
||||
<div><p class="releaseinfo">Last updated September 5, 2019</p></div>
|
||||
<div><p class="releaseinfo">Last updated March 2, 2023</p></div>
|
||||
</div>
|
||||
<hr>
|
||||
</div>
|
||||
@ -117,52 +117,58 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_int_equal" title="INT_EQUAL">INT_EQUAL</a></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_lzcount" title="LZCOUNT">LZCOUNT</a></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_int_mult" title="INT_MULT">INT_MULT</a></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_float_floor" title="FLOAT_FLOOR">FLOAT_FLOOR</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_int_notequal" title="INT_NOTEQUAL">INT_NOTEQUAL</a></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_int_equal" title="INT_EQUAL">INT_EQUAL</a></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_int_div" title="INT_DIV">INT_DIV</a></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_float_round" title="FLOAT_ROUND">FLOAT_ROUND</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_int_less" title="INT_LESS">INT_LESS</a></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_int_notequal" title="INT_NOTEQUAL">INT_NOTEQUAL</a></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_int_rem" title="INT_REM">INT_REM</a></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_float_nan" title="FLOAT_NAN">FLOAT_NAN</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_int_sless" title="INT_SLESS">INT_SLESS</a></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_int_less" title="INT_LESS">INT_LESS</a></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_int_sdiv" title="INT_SDIV">INT_SDIV</a></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_int2float" title="INT2FLOAT">INT2FLOAT</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_int_lessequal" title="INT_LESSEQUAL">INT_LESSEQUAL</a></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_int_sless" title="INT_SLESS">INT_SLESS</a></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_int_srem" title="INT_SREM">INT_SREM</a></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_float2float" title="FLOAT2FLOAT">FLOAT2FLOAT</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_int_slessequal" title="INT_SLESSEQUAL">INT_SLESSEQUAL</a></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_int_lessequal" title="INT_LESSEQUAL">INT_LESSEQUAL</a></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_bool_negate" title="BOOL_NEGATE">BOOL_NEGATE</a></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_trunc" title="TRUNC">TRUNC</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_int_zext" title="INT_ZEXT">INT_ZEXT</a></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_int_slessequal" title="INT_SLESSEQUAL">INT_SLESSEQUAL</a></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_bool_xor" title="BOOL_XOR">BOOL_XOR</a></td>
|
||||
<td><a class="link" href="pseudo-ops.html#cpui_cpoolref" title="CPOOLREF">CPOOLREF</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_int_sext" title="INT_SEXT">INT_SEXT</a></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_int_zext" title="INT_ZEXT">INT_ZEXT</a></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_bool_and" title="BOOL_AND">BOOL_AND</a></td>
|
||||
<td><a class="link" href="pseudo-ops.html#cpui_new" title="NEW">NEW</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><a class="link" href="pcodedescription.html#cpui_int_sext" title="INT_SEXT">INT_SEXT</a></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -139,6 +139,11 @@
|
||||
<td><code class="code">popcount(v0)</code></td>
|
||||
<td>Count 1 bits in v0.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>LZCOUNT</td>
|
||||
<td><code class="code">lzcount(v0)</code></td>
|
||||
<td>Counts the number of leading zero bits in v0.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>INT_EQUAL</td>
|
||||
<td><code class="code">v0 == v1</code></td>
|
||||
|
@ -27,7 +27,7 @@
|
||||
<div><h1 class="title">
|
||||
<a name="sleigh_title"></a>SLEIGH</h1></div>
|
||||
<div><h3 class="subtitle"><i>A Language for Rapid Processor Specification</i></h3></div>
|
||||
<div><p class="releaseinfo">Last updated August 24, 2022</p></div>
|
||||
<div><p class="releaseinfo">Last updated March 2, 2023</p></div>
|
||||
<div><p class="pubdate">Originally published December 16, 2005</p></div>
|
||||
</div>
|
||||
<hr>
|
||||
@ -372,7 +372,8 @@ general purpose processor instruction sets. They break up into groups.
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Logical</td>
|
||||
<td><code class="code">INT_NEGATE, INT_XOR, INT_AND, INT_OR, INT_LEFT, INT_RIGHT, INT_SRIGHT, POPCOUNT</code></td>
|
||||
<td><code class="code">INT_NEGATE, INT_XOR, INT_AND, INT_OR, INT_LEFT, INT_RIGHT, INT_SRIGHT,
|
||||
POPCOUNT, LZCOUNT</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Integer Comparison</td>
|
||||
|
@ -83,6 +83,12 @@ to lowest.
|
||||
<td>Count the number of 1 bits in v0.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code class="code">LZCOUNT</code></td>
|
||||
<td><code class="code">lzcount(v0)</code></td>
|
||||
<td>Count the number of leading 0 bits in v0.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code class="code">(simulated)</code></td>
|
||||
<td><code class="code">v0[6,1]</code></td>
|
||||
|
Loading…
Reference in New Issue
Block a user