mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-26 06:02:29 +00:00
Merge remote-tracking branch 'origin/GP-4300_MoreDivOpt' (Closes #5733)
This commit is contained in:
commit
cf616273c6
@ -86,6 +86,7 @@ model {
|
||||
include "emulateutil.cc"
|
||||
include "flow.cc"
|
||||
include "userop.cc"
|
||||
include "multiprecision.cc"
|
||||
include "funcdata.cc"
|
||||
include "funcdata_block.cc"
|
||||
include "funcdata_varnode.cc"
|
||||
|
@ -19,6 +19,7 @@ src/decompile/datatests/convert.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/deadvolatile.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/deindirect.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/displayformat.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/divopt.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/dupptr.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/elseif.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/floatprint.xml||GHIDRA||||END|
|
||||
|
@ -80,7 +80,7 @@ CORE= xml marshal space float address pcoderaw translate opcodes globalcontext
|
||||
# Additional core files for any projects that decompile
|
||||
DECCORE=capability architecture options graph cover block cast typeop database cpool \
|
||||
comment stringmanage modelrules fspec action loadimage grammar varnode op \
|
||||
type variable varmap jumptable emulate emulateutil flow userop \
|
||||
type variable varmap jumptable emulate emulateutil flow userop multiprecision \
|
||||
funcdata funcdata_block funcdata_op funcdata_varnode unionresolve pcodeinject \
|
||||
heritage prefersplit rangeutil ruleaction subflow blockaction merge double \
|
||||
transform coreaction condexe override dynamic crc32 prettyprint \
|
||||
|
@ -831,133 +831,4 @@ int4 bit_transitions(uintb val,int4 sz)
|
||||
return res;
|
||||
}
|
||||
|
||||
/// \brief Multiply 2 unsigned 64-bit values, producing a 128-bit value
|
||||
///
|
||||
/// TODO: Remove once we import a full multiprecision library.
|
||||
/// \param res points to the result array (2 uint8 pieces)
|
||||
/// \param x is the first 64-bit value
|
||||
/// \param y is the second 64-bit value
|
||||
void mult64to128(uint8 *res,uint8 x,uint8 y)
|
||||
|
||||
{
|
||||
uint8 f = x & 0xffffffff;
|
||||
uint8 e = x >> 32;
|
||||
uint8 d = y & 0xffffffff;
|
||||
uint8 c = y >> 32;
|
||||
uint8 fd = f * d;
|
||||
uint8 fc = f * c;
|
||||
uint8 ed = e * d;
|
||||
uint8 ec = e * c;
|
||||
uint8 tmp = (fd >> 32) + (fc & 0xffffffff) + (ed & 0xffffffff);
|
||||
res[1] = (tmp>>32) + (fc>>32) + (ed>>32) + ec;
|
||||
res[0] = (tmp<<32) + (fd & 0xffffffff);
|
||||
}
|
||||
|
||||
/// \brief Subtract (in-place) a 128-bit value from a base 128-value
|
||||
///
|
||||
/// The base value is altered in place.
|
||||
/// TODO: Remove once we import a full multiprecision library.
|
||||
/// \param a is the base 128-bit value being subtracted from in-place
|
||||
/// \param b is the other 128-bit value being subtracted
|
||||
void unsignedSubtract128(uint8 *a,uint8 *b)
|
||||
|
||||
{
|
||||
bool borrow = (a[0] < b[0]);
|
||||
a[0] -= b[0];
|
||||
a[1] -= b[1];
|
||||
if (borrow)
|
||||
a[1] -= 1;
|
||||
}
|
||||
|
||||
/// \brief Compare two unsigned 128-bit values
|
||||
///
|
||||
/// TODO: Remove once we import a full multiprecision library.
|
||||
/// Given a first and second value, return -1, 0, or 1 depending on whether the first value
|
||||
/// is \e less, \e equal, or \e greater than the second value.
|
||||
/// \param a is the first 128-bit value (as an array of 2 uint8 elements)
|
||||
/// \param b is the second 128-bit value
|
||||
/// \return the comparison code
|
||||
int4 unsignedCompare128(uint8 *a,uint8 *b)
|
||||
|
||||
{
|
||||
if (a[1] != b[1])
|
||||
return (a[1] < b[1]) ? -1 : 1;
|
||||
if (a[0] != b[0])
|
||||
return (a[0] < b[0]) ? -1 : 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// \brief Unsigned division of a power of 2 (upto 2^127) by a 64-bit divisor
|
||||
///
|
||||
/// The result must be less than 2^64. The remainder is calculated.
|
||||
/// \param n is the power of 2 for the numerand
|
||||
/// \param divisor is the 64-bit divisor
|
||||
/// \param q is the passed back 64-bit quotient
|
||||
/// \param r is the passed back 64-bit remainder
|
||||
/// \return 0 if successful, 1 if result is too big, 2 if divide by 0
|
||||
int4 power2Divide(int4 n,uint8 divisor,uint8 &q,uint8 &r)
|
||||
|
||||
{
|
||||
if (divisor == 0) return 2;
|
||||
uint8 power = 1;
|
||||
if (n < 64) {
|
||||
power <<= n;
|
||||
q = power / divisor;
|
||||
r = power % divisor;
|
||||
return 0;
|
||||
}
|
||||
// Divide numerand and divisor by 2^(n-63) to get approximation of result
|
||||
uint8 y = divisor >> (n-64); // Most of the way on divisor
|
||||
if (y == 0) return 1; // Check if result will be too big
|
||||
y >>= 1; // Divide divisor by final bit
|
||||
power <<= 63;
|
||||
uint8 max;
|
||||
if (y == 0) {
|
||||
max = 0;
|
||||
max -= 1; // Could be maximal
|
||||
// Check if divisor is a power of 2
|
||||
if ((((uint8)1) << (n-64)) == divisor)
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
max = power / y + 1;
|
||||
uint8 min = power / (y+1);
|
||||
if (min != 0)
|
||||
min -= 1;
|
||||
uint8 fullpower[2];
|
||||
fullpower[1] = ((uint8)1)<<(n-64);
|
||||
fullpower[0] = 0;
|
||||
uint8 mult[2];
|
||||
mult[0] = 0;
|
||||
mult[1] = 0;
|
||||
uint8 tmpq = 0;
|
||||
while(max > min+1) {
|
||||
tmpq = max + min;
|
||||
if (tmpq < min) {
|
||||
tmpq = (tmpq>>1) + 0x8000000000000000L;
|
||||
}
|
||||
else
|
||||
tmpq >>= 1;
|
||||
mult64to128(mult,divisor,tmpq);
|
||||
if (unsignedCompare128(fullpower,mult) < 0)
|
||||
max = tmpq-1;
|
||||
else
|
||||
min = tmpq;
|
||||
}
|
||||
// min is now our putative quotient
|
||||
if (tmpq != min)
|
||||
mult64to128(mult,divisor,min);
|
||||
unsignedSubtract128(fullpower,mult); // Calculate remainder
|
||||
// min might be 1 too small
|
||||
if (fullpower[1] != 0 || fullpower[0] >= divisor) {
|
||||
q = min + 1;
|
||||
r = fullpower[0] - divisor;
|
||||
}
|
||||
else {
|
||||
q = min;
|
||||
r = fullpower[0];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // End namespace ghidra
|
||||
|
@ -577,10 +577,5 @@ extern int4 count_leading_zeros(uintb val); ///< Return the number of leading z
|
||||
extern uintb coveringmask(uintb val); ///< Return a mask that \e covers the given value
|
||||
extern int4 bit_transitions(uintb val,int4 sz); ///< Calculate the number of bit transitions in the sized value
|
||||
|
||||
extern void mult64to128(uint8 *res,uint8 x,uint8 y);
|
||||
extern void unsignedSubtract128(uint8 *a,uint8 *b);
|
||||
extern int4 unsignedCompare128(uint8 *a,uint8 *b);
|
||||
extern int4 power2Divide(int4 n,uint8 divisor,uint8 &q,uint8 &r);
|
||||
|
||||
} // End namespace ghidra
|
||||
#endif
|
||||
|
@ -1600,6 +1600,15 @@ void ParamListStandardOut::initialize(void)
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Find the return value storage using the older \e fallback method
|
||||
///
|
||||
/// Given the active set of trial locations that might hold (pieces of) the return value, calculate
|
||||
/// the best matching ParamEntry from \b this ParamList and mark all the trials that are contained
|
||||
/// in the ParamEntry as \e used. If \b firstOnly is \b true, the ParamList is assumed to contain
|
||||
/// partial storage locations that might get used for return values split storage. In this case,
|
||||
/// only the first ParamEntry in a storage class is allowed to match.
|
||||
/// \param active is the set of active trials
|
||||
/// \param firstOnly is \b true if only the first entry in a storage class can match
|
||||
void ParamListStandardOut::fillinMapFallback(ParamActive *active,bool firstOnly) const
|
||||
|
||||
{
|
||||
|
@ -286,6 +286,7 @@ public:
|
||||
Varnode *newUnique(int4 s,Datatype *ct=(Datatype *)0); ///< Create a new \e temporary Varnode
|
||||
Varnode *newCodeRef(const Address &m); ///< Create a code address \e annotation Varnode
|
||||
Varnode *setInputVarnode(Varnode *vn); ///< Mark a Varnode as an input to the function
|
||||
Varnode *newExtendedConstant(int4 s,uint8 *val,PcodeOp *op); ///< Create extended precision constant
|
||||
void adjustInputVarnodes(const Address &addr,int4 sz);
|
||||
void deleteVarnode(Varnode *vn) { vbank.destroy(vn); } ///< Delete the given varnode
|
||||
|
||||
|
@ -372,6 +372,36 @@ Varnode *Funcdata::setInputVarnode(Varnode *vn)
|
||||
return vn;
|
||||
}
|
||||
|
||||
/// Construct a constant Varnode up to 128 bits, using INT_ZEXT and PIECE if necessary.
|
||||
/// This method is temporary until we have full extended precision constants.
|
||||
/// \param s is the size of the Varnode in bytes
|
||||
/// \param val is the 128-bit value in 2 64-bit chunks
|
||||
/// \param op is point before which any new PcodeOp should get inserted
|
||||
/// \return the new effective constant Varnode
|
||||
Varnode *Funcdata::newExtendedConstant(int4 s,uint8 *val,PcodeOp *op)
|
||||
|
||||
{
|
||||
if (s <= 8)
|
||||
return newConstant(s, val[0]);
|
||||
Varnode *newConstVn;
|
||||
if (val[1] == 0) {
|
||||
PcodeOp *extOp = newOp(1,op->getAddr());
|
||||
opSetOpcode(extOp,CPUI_INT_ZEXT);
|
||||
newConstVn = newUniqueOut(s,extOp);
|
||||
opSetInput(extOp,newConstant(8,val[0]),0);
|
||||
opInsertBefore(extOp,op);
|
||||
}
|
||||
else {
|
||||
PcodeOp *pieceOp = newOp(2,op->getAddr());
|
||||
opSetOpcode(pieceOp,CPUI_PIECE);
|
||||
newConstVn = newUniqueOut(s,pieceOp);
|
||||
opSetInput(pieceOp,newConstant(8,val[1]),0); // Most significant piece
|
||||
opSetInput(pieceOp,newConstant(8,val[0]),1); // Least significant piece
|
||||
opInsertBefore(pieceOp,op);
|
||||
}
|
||||
return newConstVn;
|
||||
}
|
||||
|
||||
/// \brief Adjust input Varnodes contained in the given range
|
||||
///
|
||||
/// After this call, a single \e input Varnode will exist that fills the given range.
|
||||
|
@ -54,6 +54,7 @@ class PrimitiveExtractor {
|
||||
union_invalid = 16 ///< Unions are treated as an illegal element
|
||||
};
|
||||
public:
|
||||
/// \brief A primitive data-type and its offset within the containing data-type
|
||||
class Primitive {
|
||||
public:
|
||||
Datatype *dt; ///< Primitive data-type
|
||||
@ -71,7 +72,7 @@ public:
|
||||
PrimitiveExtractor(Datatype *dt,bool unionIllegal,int4 offset,int4 max); ///< Constructor
|
||||
int4 size(void) const { return primitives.size(); } ///< Return the number of primitives extracted
|
||||
const Primitive &get(int4 i) const { return primitives[i]; } ///< Get a particular primitive
|
||||
bool isValid(void) const { return (flags & invalid) == 0; }
|
||||
bool isValid(void) const { return (flags & invalid) == 0; } ///< Return \b true if primitives were successfully extracted
|
||||
bool containsUnknown(void) const { return (flags & unknown_element)!=0; } ///< Are there \b unknown elements
|
||||
bool isAligned(void) const { return (flags & unaligned)==0; } ///< Are all elements aligned
|
||||
bool containsHoles(void) const { return (flags & extra_space)!=0; } ///< Is there empty space that is not padding
|
||||
|
334
Ghidra/Features/Decompiler/src/decompile/cpp/multiprecision.cc
Normal file
334
Ghidra/Features/Decompiler/src/decompile/cpp/multiprecision.cc
Normal file
@ -0,0 +1,334 @@
|
||||
/* ###
|
||||
* 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.
|
||||
*/
|
||||
#include "multiprecision.hh"
|
||||
|
||||
namespace ghidra {
|
||||
|
||||
extern int4 count_leading_zeros(uintb val); ///< Return the number of leading zero bits in the given value
|
||||
|
||||
/// \brief Multi-precision logical left shift by a constant amount
|
||||
///
|
||||
/// \b in and \b out arrays are specified and can point to the same storage.
|
||||
/// \param num is the number 64-bit words in the extended precision integers
|
||||
/// \param in is the 128-bit value to shift
|
||||
/// \param out is the container for the 128-bit result
|
||||
/// \param sa is the number of bits to shift
|
||||
static void leftshift(int4 num,uint8 *in,uint8 *out,int4 sa)
|
||||
|
||||
{
|
||||
int4 inIndex = num - 1 - sa / 64;
|
||||
sa = sa % 64;
|
||||
int4 outIndex = num - 1;
|
||||
if (sa == 0) {
|
||||
for(;inIndex>=0;--inIndex) {
|
||||
out[outIndex--] = in[inIndex];
|
||||
}
|
||||
for(;outIndex>=0;--outIndex) {
|
||||
out[outIndex] = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(;inIndex>0;--inIndex) {
|
||||
out[outIndex--] = (in[inIndex] << sa) | (in[inIndex-1] >> (64-sa));
|
||||
}
|
||||
out[outIndex--] = in[0] << sa;
|
||||
for(;outIndex>=0;--outIndex) {
|
||||
out[outIndex] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// \param in is the 128-bit input (as 2 64-bit words)
|
||||
/// \param out will hold the 128-bit result
|
||||
/// \param sa is the number of bits to shift
|
||||
void leftshift128(uint8 *in,uint8 *out,int4 sa)
|
||||
|
||||
{
|
||||
leftshift(2,in,out,sa);
|
||||
}
|
||||
|
||||
/// \brief Compare two multi-precision unsigned integers
|
||||
///
|
||||
/// -1, 0, or 1 is returned depending on if the first integer is less than, equal to, or greater than
|
||||
/// the second integer.
|
||||
/// \param num is the number 64-bit words in the extended precision integers
|
||||
/// \param in1 is the first integer to compare
|
||||
/// \param in2 is the second integer to compare
|
||||
/// \return -1, 0, or 1
|
||||
static inline int4 ucompare(int4 num,uint8 *in1,uint8 *in2)
|
||||
|
||||
{
|
||||
for(int4 i=num-1;i>=0;--i) {
|
||||
if (in1[i] != in2[i])
|
||||
return (in1[i] < in2[i]) ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// \param in1 is the first 128-bit value (as 2 64-bit words) to compare
|
||||
/// \param in2 is the second 128-bit value
|
||||
/// \return \b true if the first value is less than the second value
|
||||
bool uless128(uint8 *in1,uint8 *in2)
|
||||
|
||||
{
|
||||
return ucompare(2,in1,in2) < 0;
|
||||
}
|
||||
|
||||
/// \param in1 is the first 128-bit value (as 2 64-bit words) to compare
|
||||
/// \param in2 is the second 128-bit value
|
||||
/// \return \b true if the first value is less than or equal to the second value
|
||||
bool ulessequal128(uint8 *in1,uint8 *in2)
|
||||
|
||||
{
|
||||
return ucompare(2,in1,in2) <= 0;
|
||||
}
|
||||
|
||||
/// \brief Multi-precision add operation
|
||||
///
|
||||
/// \param num is the number 64-bit words in the extended precision integers
|
||||
/// \param in1 is the first integer
|
||||
/// \param in2 is the integer added to the first
|
||||
/// \param out is where the add result is stored
|
||||
static inline void add(int4 num,uint8 *in1,uint8 *in2,uint8 *out)
|
||||
|
||||
{
|
||||
uint8 carry = 0;
|
||||
for(int4 i=0;i<num;++i) {
|
||||
uint8 tmp = in2[i] + carry;
|
||||
uint8 tmp2 = in1[i] + tmp;
|
||||
out[i] = tmp2;
|
||||
carry = (tmp < in2[i] || tmp2 < tmp) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// \param in1 is the first 128-bit value (as 2 64-bit words) to add
|
||||
/// \param in2 is the second 128-bit value to add
|
||||
/// \param out will hold the 128-bit result
|
||||
void add128(uint8 *in1,uint8 *in2,uint8 *out)
|
||||
|
||||
{
|
||||
add(2,in1,in2,out);
|
||||
}
|
||||
|
||||
/// \brief Multi-precision subtract operation
|
||||
///
|
||||
/// \param num is the number 64-bit words in the extended precision integers
|
||||
/// \param in1 is the first integer
|
||||
/// \param in2 is the integer subtracted from the first
|
||||
/// \param out is where the subtraction result is stored
|
||||
static inline void subtract(int4 num,uint8 *in1,uint8 *in2,uint8 *out)
|
||||
|
||||
{
|
||||
uint8 borrow = 0;
|
||||
for(int4 i=0;i<num;++i) {
|
||||
uint8 tmp = in2[i] + borrow;
|
||||
borrow = (tmp < in2[i] || in1[i] < tmp) ? 1: 0;
|
||||
out[i] = in1[i] - tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/// \param in1 is the first 128-bit value (as 2 64-bit words)
|
||||
/// \param in2 is the second 128-bit value to subtract
|
||||
/// \param out will hold the 128-bit result
|
||||
void subtract128(uint8 *in1,uint8 *in2,uint8 *out)
|
||||
|
||||
{
|
||||
subtract(2,in1,in2,out);
|
||||
}
|
||||
|
||||
/// \brief Split an array of 64-bit words into an array of 32-bit words
|
||||
///
|
||||
/// The arrays must already be allocated. The least significant half of each 64-bit word is put
|
||||
/// into the 32-bit word array first. The index of the most significant non-zero 32-bit word is
|
||||
/// calculated and returned as the \e effective size of the resulting array.
|
||||
/// \param num is the number of 64-bit words to split
|
||||
/// \param val is the array of 64-bit words
|
||||
/// \param res is the array that will hold the 32-bit words
|
||||
/// \return the effective size of the 32-bit word array
|
||||
static int4 split64_32(int4 num,uint8 *val,uint4 *res)
|
||||
|
||||
{
|
||||
int4 m = 0;
|
||||
for(int4 i=0;i<num;++i) {
|
||||
uint4 hi = val[i] >> 32;
|
||||
uint4 lo = val[i] & 0xffffffff;
|
||||
if (hi != 0)
|
||||
m = i*2 + 2;
|
||||
else if (lo != 0)
|
||||
m = i*2 + 1;
|
||||
res[i*2] = lo;
|
||||
res[i*2+1] = hi;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
/// \brief Pack an array of 32-bit words into an array of 64-bit words
|
||||
///
|
||||
/// The arrays must already be allocated. The 64-bit word array is padded out with zeroes if
|
||||
/// the specified size exceeds the provided number of 32-bit words.
|
||||
/// \param num is the number of 64-bit words in the resulting array
|
||||
/// \param max is the number of 32-bit words to pack
|
||||
/// \param out is the array of 64-bit words
|
||||
/// \param in is the array of 32-bit words
|
||||
static void pack32_64(int4 num,int4 max,uint8 *out,uint4 *in)
|
||||
|
||||
{
|
||||
int4 j = num * 2 - 1;
|
||||
for(int4 i=num-1;i>=0;--i) {
|
||||
uint8 val;
|
||||
val = (j<max) ? in[j] : 0;
|
||||
val <<= 32;
|
||||
j -= 1;
|
||||
if (j < max)
|
||||
val |= in[j];
|
||||
j -= 1;
|
||||
out[i] = val;
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Logical shift left for an extended integer in 32-bit word arrays
|
||||
///
|
||||
/// \param arr is the array of 32-bit words
|
||||
/// \param size is the number of words in the array
|
||||
/// \param sa is the number of bits to shift
|
||||
static void shift_left(uint4 *arr,int4 size,int4 sa)
|
||||
|
||||
{
|
||||
if (sa == 0) return;
|
||||
for (int4 i = size - 1; i > 0; --i)
|
||||
arr[i] = (arr[i] << sa) | (arr[i-1] >> (32-sa));
|
||||
arr[0] = arr[0] << sa;
|
||||
}
|
||||
|
||||
/// \brief Logical shift right for an extended integer in 32-bit word arrays
|
||||
///
|
||||
/// \param arr is the array of 32-bit words
|
||||
/// \param size is the number of words in the array
|
||||
/// \param sa is the number of bits to shift
|
||||
static void shift_right(uint4 *arr,int4 size,int4 sa)
|
||||
|
||||
{
|
||||
if (sa == 0) return;
|
||||
for(int4 i=0;i<size-1;++i)
|
||||
arr[i] = (arr[i] >> sa) | (arr[i+1] << (32-sa));
|
||||
arr[size-1] = arr[size -1] >> sa;
|
||||
}
|
||||
|
||||
/// \brief Knuth's algorithm d, for integer division
|
||||
///
|
||||
/// The numerator and denominator, expressed in 32-bit \e digits, are provided.
|
||||
/// The algorithm calculates the quotient and the remainder is left in the array originally
|
||||
/// containing the numerator.
|
||||
/// \param m is the number of 32-bit digits in the numerator
|
||||
/// \param n is the number of 32-bit digits in the denominator
|
||||
/// \param u is the numerator and will hold the remainder
|
||||
/// \param v is the denominator
|
||||
/// \param q will hold the final quotient
|
||||
static void knuth_algorithm_d(int4 m,int4 n,uint4 *u,uint4 *v,uint4 *q)
|
||||
|
||||
{
|
||||
int4 s = count_leading_zeros(v[n-1]) - 8*(sizeof(uintb)-sizeof(uint4));
|
||||
shift_left(v,n,s);
|
||||
shift_left(u,m,s);
|
||||
|
||||
for(int4 j=m-n-1;j>=0;--j) {
|
||||
uint8 tmp = ((uint8)u[n+j] << 32) + u[n-1+j];
|
||||
uint8 qhat = tmp / v[n-1];
|
||||
uint8 rhat = tmp % v[n-1];
|
||||
do {
|
||||
if (qhat <= 0xffffffff && qhat * v[n-2] <= (rhat << 32) + u[n-2+j])
|
||||
break;
|
||||
qhat -= 1;
|
||||
rhat += v[n-1];
|
||||
} while(rhat <= 0xffffffff);
|
||||
|
||||
uint8 carry = 0;
|
||||
int8 t;
|
||||
for (int4 i=0;i<n;++i) {
|
||||
tmp = qhat*v[i];
|
||||
t = u[i+j] - carry - (tmp & 0xffffffff);
|
||||
u[i+j] = t;
|
||||
carry = (tmp >> 32) - (t >> 32);
|
||||
}
|
||||
t = u[j+n] - carry;
|
||||
u[j+n] = t;
|
||||
|
||||
q[j] = qhat;
|
||||
if (t < 0) {
|
||||
q[j] -= 1;
|
||||
carry = 0;
|
||||
for(int4 i=0;i<n;++i) {
|
||||
tmp = u[i+j] + (v[i] + carry);
|
||||
u[i+j] = tmp;
|
||||
carry = tmp >> 32;
|
||||
}
|
||||
u[j+n] += carry;
|
||||
}
|
||||
}
|
||||
shift_right(u,m,s);
|
||||
}
|
||||
|
||||
/// \param numer holds the 2 64-bit words of the numerator
|
||||
/// \param denom holds the 2 words of the denominator
|
||||
/// \param quotient_res will hold the 2 words of the quotient
|
||||
/// \param remainder_res will hold the 2 words of the remainder
|
||||
void udiv128(uint8 *numer,uint8 *denom,uint8 *quotient_res,uint8 *remainder_res)
|
||||
|
||||
{
|
||||
if (numer[1] == 0 && denom[1] == 0) {
|
||||
quotient_res[0] = numer[0] / denom[0];
|
||||
quotient_res[1] = 0;
|
||||
remainder_res[0] = numer[0] % denom[0];
|
||||
remainder_res[1] = 0;
|
||||
return;
|
||||
}
|
||||
uint4 v[4];
|
||||
uint4 u[5]; // Array needs one more entry for normalization overflow
|
||||
uint4 q[4];
|
||||
int4 n = split64_32(2,denom,v);
|
||||
if (n == 0) {
|
||||
throw LowlevelError("divide by 0");
|
||||
}
|
||||
int4 m = split64_32(2,numer,u);
|
||||
if ( m < n || ( (n==m) && u[n-1] < v[n-1])) {
|
||||
// denominator is smaller than the numerator, quotient is 0
|
||||
quotient_res[0] = 0;
|
||||
quotient_res[1] = 0;
|
||||
remainder_res[0] = numer[0];
|
||||
remainder_res[1] = numer[1];
|
||||
return;
|
||||
}
|
||||
u[m] = 0;
|
||||
m += 1; // Extend u array by 1 to account for normalization
|
||||
if (n == 1) {
|
||||
uint4 d = v[0];
|
||||
uint4 rem = 0;
|
||||
for(int4 i=m-1;i>=0;--i) {
|
||||
uint8 tmp = ((uint8)rem << 32) + u[i];
|
||||
q[i] = tmp / d;
|
||||
u[i] = 0;
|
||||
rem = tmp % d;
|
||||
}
|
||||
u[0] = rem; // Last carry is final remainder
|
||||
}
|
||||
else {
|
||||
knuth_algorithm_d(m,n,u,v,q);
|
||||
}
|
||||
pack32_64(2,m-n,quotient_res,q);
|
||||
pack32_64(2,m-1,remainder_res,u);
|
||||
}
|
||||
|
||||
} // End namespace ghidra
|
@ -0,0 +1,42 @@
|
||||
/* ###
|
||||
* 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.
|
||||
*/
|
||||
/// \file multiprecision.hh
|
||||
/// \brief Multi-precision integers
|
||||
#ifndef __CPUI_MULTIPRECISION__
|
||||
#define __CPUI_MULTIPRECISION__
|
||||
|
||||
#include "error.hh"
|
||||
|
||||
namespace ghidra {
|
||||
|
||||
extern void leftshift128(uint8 *in,uint8 *out,int4 sa); ///< 128-bit INT_LEFT operation with constant shift amount
|
||||
extern bool uless128(uint8 *in1,uint8 *in2); ///< 128-bit INT_LESS operation
|
||||
extern bool ulessequal128(uint8 *in1,uint8 *in2); ///< 128-bit INT_LESSEQUAL operation
|
||||
extern void udiv128(uint8 *numer,uint8 *denom,uint8 *quotient_res,uint8 *remainder_res); ///< 128-bit INT_DIV
|
||||
extern void add128(uint8 *in1,uint8 *in2,uint8 *out); ///< 128-bit INT_ADD operation
|
||||
extern void subtract128(uint8 *in1,uint8 *in2,uint8 *out); ///< 128-bit INT_SUB operation
|
||||
|
||||
/// \brief Set a 128-bit value (2 64-bit words) from a 64-bit value
|
||||
///
|
||||
/// \param res will hold the 128-bit value
|
||||
/// \param val is the 64-bit value to set from
|
||||
inline void set_u128(uint8 *res,uint8 val) {
|
||||
res[0] = val;
|
||||
res[1] = 0;
|
||||
}
|
||||
|
||||
} // End namespace ghidra
|
||||
#endif
|
@ -17,6 +17,7 @@
|
||||
#include "coreaction.hh"
|
||||
#include "subflow.hh"
|
||||
#include "rangeutil.hh"
|
||||
#include "multiprecision.hh"
|
||||
|
||||
namespace ghidra {
|
||||
|
||||
@ -1884,8 +1885,12 @@ int4 RuleDoubleShift::applyOp(PcodeOp *op,Funcdata &data)
|
||||
}
|
||||
else if (sa1 == sa2 && size <= sizeof(uintb)) { // FIXME: precision
|
||||
mask = calc_mask(size);
|
||||
if (opc1 == CPUI_INT_LEFT)
|
||||
if (opc1 == CPUI_INT_LEFT) {
|
||||
// The INT_LEFT is highly likely to be a multiply, so don't collapse to an INT_AND if there
|
||||
// are other uses of the intermediate value.
|
||||
if (secvn->loneDescend() == (PcodeOp *)0) return 0;
|
||||
mask = (mask<<sa1) & mask;
|
||||
}
|
||||
else
|
||||
mask = (mask>>sa1) & mask;
|
||||
newvn = data.newConstant(size,mask);
|
||||
@ -7359,16 +7364,15 @@ int4 RuleDivTermAdd::applyOp(PcodeOp *op,Funcdata &data)
|
||||
OpCode shiftopc;
|
||||
PcodeOp *subop = findSubshift(op,n,shiftopc);
|
||||
if (subop == (PcodeOp *)0) return 0;
|
||||
// TODO: Cannot currently support 128-bit arithmetic, except in special case of 2^64
|
||||
if (n > 64) return 0;
|
||||
if (n > 127) return 0; // Up to 128-bits
|
||||
|
||||
Varnode *multvn = subop->getIn(0);
|
||||
if (!multvn->isWritten()) return 0;
|
||||
PcodeOp *multop = multvn->getDef();
|
||||
if (multop->code() != CPUI_INT_MULT) return 0;
|
||||
uintb multConst;
|
||||
int4 constExtType = multop->getIn(1)->isConstantExtended(multConst);
|
||||
if (constExtType < 0) return 0;
|
||||
uint8 multConst[2];
|
||||
if (!multop->getIn(1)->isConstantExtended(multConst))
|
||||
return 0;
|
||||
|
||||
Varnode *extvn = multop->getIn(0);
|
||||
if (!extvn->isWritten()) return 0;
|
||||
@ -7381,20 +7385,10 @@ int4 RuleDivTermAdd::applyOp(PcodeOp *op,Funcdata &data)
|
||||
if (op->code()==CPUI_INT_RIGHT) return 0;
|
||||
}
|
||||
|
||||
uintb newc;
|
||||
if (n < 64 || (extvn->getSize() <= 8)) {
|
||||
uintb pow = 1;
|
||||
pow <<= n; // Calculate 2^n
|
||||
newc = multConst + pow;
|
||||
}
|
||||
else {
|
||||
if (constExtType != 2) return 0; // TODO: Can't currently represent
|
||||
if (!signbit_negative(multConst,8)) return 0;
|
||||
// Adding 2^64 to a sign-extended 64-bit value with its sign set, causes all the
|
||||
// set extension bits to be cancelled out, converting it into a
|
||||
// zero-extended 64-bit value.
|
||||
constExtType = 1; // Set extension of constant to INT_ZEXT
|
||||
}
|
||||
uint8 power[2];
|
||||
set_u128(power, 1);
|
||||
leftshift128(power,power,n); // power = 2^n
|
||||
add128(multConst,power,multConst); // multConst += 2^n
|
||||
Varnode *x = extop->getIn(0);
|
||||
|
||||
list<PcodeOp *>::const_iterator iter;
|
||||
@ -7405,17 +7399,7 @@ int4 RuleDivTermAdd::applyOp(PcodeOp *op,Funcdata &data)
|
||||
continue;
|
||||
|
||||
// Construct the new constant
|
||||
Varnode *newConstVn;
|
||||
if (constExtType == 0)
|
||||
newConstVn = data.newConstant(extvn->getSize(),newc);
|
||||
else {
|
||||
// Create new extension of the constant
|
||||
PcodeOp *newExtOp = data.newOp(1,op->getAddr());
|
||||
data.opSetOpcode(newExtOp,(constExtType==1) ? CPUI_INT_ZEXT : CPUI_INT_SEXT);
|
||||
newConstVn = data.newUniqueOut(extvn->getSize(),newExtOp);
|
||||
data.opSetInput(newExtOp,data.newConstant(8,multConst),0);
|
||||
data.opInsertBefore(newExtOp,op);
|
||||
}
|
||||
Varnode *newConstVn = data.newExtendedConstant(extvn->getSize(), multConst, op);
|
||||
|
||||
// Construct the new multiply
|
||||
PcodeOp *newmultop = data.newOp(2,op->getAddr());
|
||||
@ -7532,7 +7516,8 @@ int4 RuleDivTermAdd2::applyOp(PcodeOp *op,Funcdata &data)
|
||||
if (!multvn->isWritten()) return 0;
|
||||
PcodeOp *multop = multvn->getDef();
|
||||
if (multop->code() != CPUI_INT_MULT) return 0;
|
||||
if (!multop->getIn(1)->isConstant()) return 0;
|
||||
uint8 multConst[2];
|
||||
if (!multop->getIn(1)->isConstantExtended(multConst)) return 0;
|
||||
Varnode *zextvn = multop->getIn(0);
|
||||
if (!zextvn->isWritten()) return 0;
|
||||
PcodeOp *zextop = zextvn->getDef();
|
||||
@ -7545,14 +7530,16 @@ int4 RuleDivTermAdd2::applyOp(PcodeOp *op,Funcdata &data)
|
||||
if (addop->code() != CPUI_INT_ADD) continue;
|
||||
if ((addop->getIn(0)!=z)&&(addop->getIn(1)!=z)) continue;
|
||||
|
||||
uintb pow = 1;
|
||||
pow <<= n; // Calculate 2^n
|
||||
uintb newc = multop->getIn(1)->getOffset() + pow;
|
||||
uint8 pow[2];
|
||||
set_u128(pow, 1);
|
||||
leftshift128(pow,pow,n); // Calculate 2^n
|
||||
add128(multConst, pow, multConst); // multConst = multConst + 2^n
|
||||
PcodeOp *newmultop = data.newOp(2,op->getAddr());
|
||||
data.opSetOpcode(newmultop,CPUI_INT_MULT);
|
||||
Varnode *newmultvn = data.newUniqueOut(zextvn->getSize(),newmultop);
|
||||
data.opSetInput(newmultop,zextvn,0);
|
||||
data.opSetInput(newmultop,data.newConstant(zextvn->getSize(),newc),1);
|
||||
Varnode *newConstVn = data.newExtendedConstant(zextvn->getSize(), multConst, op);
|
||||
data.opSetInput(newmultop,newConstVn,1);
|
||||
data.opInsertBefore(newmultop,op);
|
||||
|
||||
PcodeOp *newshiftop = data.newOp(2,op->getAddr());
|
||||
@ -7591,7 +7578,7 @@ int4 RuleDivTermAdd2::applyOp(PcodeOp *op,Funcdata &data)
|
||||
/// \param xsize will hold the number of (non-zero) bits in the numerand
|
||||
/// \param extopc holds whether the extension is INT_ZEXT or INT_SEXT
|
||||
/// \return the extended numerand if possible, or the unextended numerand, or NULL
|
||||
Varnode *RuleDivOpt::findForm(PcodeOp *op,int4 &n,uintb &y,int4 &xsize,OpCode &extopc)
|
||||
Varnode *RuleDivOpt::findForm(PcodeOp *op,int4 &n,uint8 *y,int4 &xsize,OpCode &extopc)
|
||||
|
||||
{
|
||||
PcodeOp *curOp = op;
|
||||
@ -7621,18 +7608,22 @@ Varnode *RuleDivOpt::findForm(PcodeOp *op,int4 &n,uintb &y,int4 &xsize,OpCode &e
|
||||
if (curOp->code() != CPUI_INT_MULT) return (Varnode *)0; // There MUST be an INT_MULT
|
||||
Varnode *inVn = curOp->getIn(0);
|
||||
if (!inVn->isWritten()) return (Varnode *)0;
|
||||
if (inVn->isConstantExtended(y) >= 0) {
|
||||
if (inVn->isConstantExtended(y)) {
|
||||
inVn = curOp->getIn(1);
|
||||
if (!inVn->isWritten()) return (Varnode *)0;
|
||||
}
|
||||
else if (curOp->getIn(1)->isConstantExtended(y) < 0)
|
||||
else if (!curOp->getIn(1)->isConstantExtended(y))
|
||||
return (Varnode *)0; // There MUST be a constant
|
||||
|
||||
Varnode *resVn;
|
||||
PcodeOp *extOp = inVn->getDef();
|
||||
extopc = extOp->code();
|
||||
if (extopc != CPUI_INT_SEXT) {
|
||||
uintb nzMask = inVn->getNZMask();
|
||||
uintb nzMask;
|
||||
if (extopc == CPUI_INT_ZEXT)
|
||||
nzMask = extOp->getIn(0)->getNZMask();
|
||||
else
|
||||
nzMask = inVn->getNZMask();
|
||||
xsize = 8*sizeof(uintb) - count_leading_zeros(nzMask);
|
||||
if (xsize == 0) return (Varnode *)0;
|
||||
if (xsize > 4*inVn->getSize()) return (Varnode *)0;
|
||||
@ -7672,44 +7663,50 @@ Varnode *RuleDivOpt::findForm(PcodeOp *op,int4 &n,uintb &y,int4 &xsize,OpCode &e
|
||||
/// Do some additional checks on the parameters as an optimized encoding
|
||||
/// of a divisor.
|
||||
/// \param n is the power of 2
|
||||
/// \param y is the multiplicative coefficient
|
||||
/// \param y is the (up to 128-bit) multiplicative coefficient
|
||||
/// \param xsize is the maximum power of 2
|
||||
/// \return the divisor or 0 if the checks fail
|
||||
uintb RuleDivOpt::calcDivisor(uintb n,uint8 y,int4 xsize)
|
||||
uintb RuleDivOpt::calcDivisor(uintb n,uint8 *y,int4 xsize)
|
||||
|
||||
{
|
||||
if (n > 127) return 0; // Not enough precision
|
||||
if (y <= 1) return 0; // Boundary cases are wrong form
|
||||
if (n > 127 || xsize > 64) return 0; // Not enough precision
|
||||
uint8 power[2];
|
||||
uint8 q[2];
|
||||
uint8 r[2];
|
||||
set_u128(power, 1);
|
||||
if (ulessequal128(y, power)) // Boundary cases, y <= 1, are wrong form
|
||||
return 0;
|
||||
|
||||
uint8 d,r;
|
||||
uint8 power;
|
||||
if (n < 64) {
|
||||
power = ((uint8)1) << n;
|
||||
d = power / (y-1);
|
||||
r = power % (y-1);
|
||||
subtract128(y, power, y); // y = y - 1
|
||||
leftshift128(power, power, n); // power = 2^n
|
||||
|
||||
udiv128(power, y, q, r);
|
||||
if (0 != q[1])
|
||||
return 0; // Result is bigger than 64-bits
|
||||
if (uless128(y,q)) return 0; // if y < q
|
||||
uint8 diff = 0;
|
||||
if (!uless128(r,q)) { // if r >= q
|
||||
// Its possible y is 1 too big giving us a q that is smaller by 1 than the correct value
|
||||
q[0] += 1; // Adjust to bigger q
|
||||
subtract128(r,y,r); // and remainder for the smaller y
|
||||
add128(r, q, r);
|
||||
if (!uless128(r,q)) return 0;
|
||||
diff = q[0]; // Using y that is off by one adds extra error, affecting allowable maxx
|
||||
}
|
||||
else {
|
||||
if (0 != power2Divide(n,y-1,d,r))
|
||||
return 0; // Result is bigger than 64-bits
|
||||
}
|
||||
if (d>=y) return 0;
|
||||
if (r >= d) return 0;
|
||||
// The optimization of division to multiplication
|
||||
// by the reciprocal holds true, if the maximum value
|
||||
// of x times the remainder is less than 2^n
|
||||
uint8 maxx = 1;
|
||||
maxx <<= xsize;
|
||||
// of x times q-r is less than 2^n
|
||||
uint8 maxx = (xsize == 64) ? 0 : ((uint8)1) << xsize;
|
||||
maxx -= 1; // Maximum possible x value
|
||||
uint8 tmp;
|
||||
if (n < 64)
|
||||
tmp = power / (d-r); // r < d => divisor is non-zero
|
||||
else {
|
||||
uint8 unused;
|
||||
if (0 != power2Divide(n,d-r,tmp,unused))
|
||||
return (uintb)d; // tmp is bigger than 2^64 > maxx
|
||||
}
|
||||
if (tmp<=maxx) return 0;
|
||||
return (uintb)d;
|
||||
uint8 tmp[2];
|
||||
uint8 denom[2];
|
||||
diff += q[0] - r[0];
|
||||
set_u128(denom,diff);
|
||||
udiv128(power,denom, tmp, r);
|
||||
if (0 != tmp[1])
|
||||
return (uintb)q[0]; // tmp is bigger than 2^64 > maxx
|
||||
if (tmp[0]<=maxx) return 0;
|
||||
return (uintb)q[0];
|
||||
}
|
||||
|
||||
/// \brief Replace sign-bit extractions from the first given Varnode with the second Varnode
|
||||
@ -7785,7 +7782,7 @@ bool RuleDivOpt::checkFormOverlap(PcodeOp *op)
|
||||
Varnode *cvn = superOp->getIn(1);
|
||||
if (!cvn->isConstant()) return true; // Might be a form where constant has propagated yet
|
||||
int4 n,xsize;
|
||||
uintb y;
|
||||
uint8 y[2];
|
||||
OpCode extopc;
|
||||
Varnode *inVn = findForm(superOp, n, y, xsize, extopc);
|
||||
if (inVn != (Varnode *)0) return true;
|
||||
@ -7797,8 +7794,8 @@ bool RuleDivOpt::checkFormOverlap(PcodeOp *op)
|
||||
/// \brief Convert INT_MULT and shift forms into INT_DIV or INT_SDIV
|
||||
///
|
||||
/// The unsigned and signed variants are:
|
||||
/// - `sub( (zext(V)*c)>>n, 0) => V / (2^n/(c-1))`
|
||||
/// - `sub( (sext(V)*c)s>>n, 0) => V s/ (2^n/(c-1))`
|
||||
/// - `sub( (zext(V)*c), d) >> e => V / (2^n/(c-1)) where n = d*8 + e`
|
||||
/// - `sub( (sext(V)*c), d) s>> e => V s/ (2^n/(c-1)) where n = d*8 + e`
|
||||
void RuleDivOpt::getOpList(vector<uint4> &oplist) const
|
||||
|
||||
{
|
||||
@ -7811,7 +7808,7 @@ int4 RuleDivOpt::applyOp(PcodeOp *op,Funcdata &data)
|
||||
|
||||
{
|
||||
int4 n,xsize;
|
||||
uintb y;
|
||||
uint8 y[2];
|
||||
OpCode extOpc;
|
||||
Varnode *inVn = findForm(op,n,y,xsize,extOpc);
|
||||
if (inVn == (Varnode *)0) return 0;
|
||||
|
@ -1264,7 +1264,7 @@ public:
|
||||
};
|
||||
|
||||
class RuleDivOpt : public Rule {
|
||||
static uintb calcDivisor(uintb n,uint8 y,int4 xsize); ///< Calculate the divisor
|
||||
static uintb calcDivisor(uintb n,uint8 *y,int4 xsize); ///< Calculate the divisor
|
||||
static void moveSignBitExtraction(Varnode *firstVn,Varnode *replaceVn,Funcdata &data);
|
||||
static bool checkFormOverlap(PcodeOp *op); ///< If form rooted at given PcodeOp is superseded by an overlapping form
|
||||
public:
|
||||
@ -1275,7 +1275,7 @@ public:
|
||||
}
|
||||
virtual void getOpList(vector<uint4> &oplist) const;
|
||||
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
||||
static Varnode *findForm(PcodeOp *op,int4 &n,uintb &y,int4 &xsize,OpCode &extopc);
|
||||
static Varnode *findForm(PcodeOp *op,int4 &n,uint8 *y,int4 &xsize,OpCode &extopc);
|
||||
};
|
||||
|
||||
class RuleSignDiv2 : public Rule {
|
||||
|
@ -3706,6 +3706,7 @@ static void findSlaSpecs(vector<string> &res, const string &dir, const string &s
|
||||
/// \param enforceLocalKeyWord is \b true to force all local variable definitions to use the \b local keyword
|
||||
/// \param largeTemporaryWarning is \b true for individual warnings about temporary varnodes that are too large
|
||||
/// \param caseSensitiveRegisterNames is \b true if register names are allowed to be case sensitive
|
||||
/// \param debugOutput is \b true if the output file is written using the debug (XML) form of the .sla format
|
||||
void SleighCompile::setAllOptions(const map<string,string> &defines, bool unnecessaryPcodeWarning,
|
||||
bool lenientConflict, bool allCollisionWarning,
|
||||
bool allNopWarning,bool deadTempWarning,bool enforceLocalKeyWord,
|
||||
|
@ -780,37 +780,55 @@ void Varnode::printRawHeritage(ostream &s,int4 depth) const
|
||||
s << endl;
|
||||
}
|
||||
|
||||
/// If \b this is a constant, or is extended (INT_ZEXT,INT_SEXT) from a constant,
|
||||
/// the \e value of the constant is passed back and a non-negative integer is returned, either:
|
||||
/// - 0 for a normal constant Varnode
|
||||
/// - 1 for a zero extension (INT_ZEXT) of a normal constant
|
||||
/// - 2 for a sign extension (INT_SEXT) of a normal constant
|
||||
/// \param val is a reference to the constant value that is passed back
|
||||
/// \return the extension code (or -1 if \b this cannot be interpreted as a constant)
|
||||
int4 Varnode::isConstantExtended(uintb &val) const
|
||||
/// If \b this is a constant, or is extended (INT_ZEXT,INT_SEXT,PIECE) from a constant,
|
||||
/// the \e value of the constant (currently up to 128 bits) is passed back and \b true is returned.
|
||||
/// \param val will hold the 128-bit constant value
|
||||
/// \return \b true if a constant was recovered
|
||||
bool Varnode::isConstantExtended(uint8 *val) const
|
||||
|
||||
{
|
||||
if (isConstant()) {
|
||||
val = getOffset();
|
||||
return 0;
|
||||
val[0] = getOffset();
|
||||
val[1] = 0;
|
||||
return true;
|
||||
}
|
||||
if (!isWritten()) return -1;
|
||||
if (!isWritten() || size <= 8) return false;
|
||||
if (size > 16) return false; // Currently only up to 128-bit values
|
||||
OpCode opc = def->code();
|
||||
if (opc == CPUI_INT_ZEXT) {
|
||||
Varnode *vn0 = def->getIn(0);
|
||||
if (vn0->isConstant()) {
|
||||
val = vn0->getOffset();
|
||||
return 1;
|
||||
val[0] = vn0->getOffset();
|
||||
val[1] = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (opc == CPUI_INT_SEXT) {
|
||||
Varnode *vn0 = def->getIn(0);
|
||||
if (vn0->isConstant()) {
|
||||
val = vn0->getOffset();
|
||||
return 2;
|
||||
val[0] = vn0->getOffset();
|
||||
if (vn0->getSize() < 8)
|
||||
val[0] = sign_extend(val[0], vn0->getSize(), size);
|
||||
val[1] = (signbit_negative(val[0], 8)) ? 0xffffffffffffffffL : 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
else if (opc == CPUI_PIECE) {
|
||||
Varnode *vnlo = def->getIn(1);
|
||||
if (vnlo->isConstant()) {
|
||||
val[0] = vnlo->getOffset();
|
||||
Varnode *vnhi = def->getIn(0);
|
||||
if (vnhi->isConstant()) {
|
||||
val[1] = vnhi->getOffset();
|
||||
if (vnlo->getSize() == 8)
|
||||
return true;
|
||||
val[0] |= val[1] << 8*vnlo->getSize();
|
||||
val[1] >>= 8*(8-vnlo->getSize());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Make an initial determination of the Datatype of this Varnode. If a Datatype is already
|
||||
|
@ -290,7 +290,7 @@ public:
|
||||
return (loc.getOffset() == val);
|
||||
}
|
||||
|
||||
int4 isConstantExtended(uintb &val) const; ///< Is \b this an (extended) constant
|
||||
bool isConstantExtended(uint8 *val) const; ///< Is \b this an (extended) constant
|
||||
/// Return \b true if this Varnode is linked into the SSA tree
|
||||
bool isHeritageKnown(void) const { return ((flags&(Varnode::insert|Varnode::constant|Varnode::annotation))!=0); }
|
||||
bool isTypeLock(void) const { return ((flags&Varnode::typelock)!=0); } ///< Does \b this have a locked Datatype?
|
||||
|
292
Ghidra/Features/Decompiler/src/decompile/datatests/divopt.xml
Normal file
292
Ghidra/Features/Decompiler/src/decompile/datatests/divopt.xml
Normal file
@ -0,0 +1,292 @@
|
||||
<decompilertest>
|
||||
<binaryimage arch="x86:LE:64:default:gcc">
|
||||
<!-- Examples of optimized division and modulo for constants
|
||||
81 89 91 93 95 97 99 101 103 107 111 112 115 119 121 123 125 -->
|
||||
<bytechunk space="ram" offset="0x100000" readonly="true">
|
||||
f30f1efa48ba53069e6ecd0f8b94488b
|
||||
0f4889c848f7e24829d148d1e94801ca
|
||||
488b4f0848c1ea064889c848891748ba
|
||||
e10217b8c0052e7048f7e24829d148d1
|
||||
e94801ca488b4f1048c1ea064889c848
|
||||
89570848ba176881166881166848f7e2
|
||||
4829d148d1e94801ca488b4f1848c1ea
|
||||
064889c84889571048ba175860810516
|
||||
586048f7e24829d148d1e94801ca488b
|
||||
4f2048c1ea064889c84889571848ba31
|
||||
d28e150823ed5848f7e24829d148d1e9
|
||||
4801ca488b4f2848c1ea064889c84889
|
||||
572048bad151812fae7ed05148f7e248
|
||||
29d148d1e94801ca488b4f3048c1ea06
|
||||
4889c84889572848ba15a8f52b056afd
|
||||
4a48f7e24829d148d1e94801ca488b4f
|
||||
3848c1ea064889c84889573048bae5ae
|
||||
9f2d56866f4448f7e24829d148d1e948
|
||||
01ca488b4f4048c1ea064889c8488957
|
||||
3848bac527904acecb223e48f7e24829
|
||||
d148d1e94801ca488b4f4848c1ea0648
|
||||
89c84889574048ba6ff60bb1a2343e32
|
||||
48f7e24829d148d1e94801ca488b4f50
|
||||
48c1ea064889c84889574848bab95073
|
||||
12880b352748f7e24829d148d1e94801
|
||||
ca48b9942449922449922448c1ea0648
|
||||
895750488b575848c1ea044889d048f7
|
||||
e1488b4f604889c84889575848ba07cf
|
||||
1128da6af01c48f7e24829d148d1e948
|
||||
01ca488b4f6848c1ea064889c8488957
|
||||
6048ba5d13815c13815c1348f7e24829
|
||||
d148d1e94801ca488b4f7048c1ea0648
|
||||
89c84889576848bae3fdc869be56cf0e
|
||||
48f7e24829d148d1e94801ca488b4f78
|
||||
48c1ea064889c84889577048ba11680a
|
||||
81a610680a48f7e24829d148d1e94801
|
||||
ca48c1ea0648895778488b8f80000000
|
||||
48ba77be9f1a2fdd24064889c848f7e2
|
||||
4829d148d1e94801ca48c1ea06488997
|
||||
80000000c30000000000000000000000
|
||||
f30f1efa48ba9581a75bf3c32265488b
|
||||
0f4889c848c1f93f48f7ea48c1fa0548
|
||||
29ca488b4f0848891748ba71810b5ce0
|
||||
0217b84889c848f7ea4801ca48c1f93f
|
||||
48c1fa064829ca488b4f104889570848
|
||||
ba032dd0022dd0022d4889c848c1f93f
|
||||
48f7ea48c1fa044829ca488b4f184889
|
||||
571048ba030b2cb0c0020b2c4889c848
|
||||
c1f93f48f7ea48c1fa044829ca488b4f
|
||||
204889571848ba1969c70a849176ac48
|
||||
89c848f7ea4801ca48c1f93f48c1fa06
|
||||
4829ca488b4f284889572048bae9a8c0
|
||||
17573fe8a84889c848f7ea4801ca48c1
|
||||
f93f48c1fa064829ca488b4f30488957
|
||||
2848ba0bd4fa9502b57ea54889c848f7
|
||||
ea4801ca48c1f93f48c1fa064829ca48
|
||||
8b4f384889573048ba73d7cf162bc337
|
||||
a24889c848f7ea4801ca48c1f93f48c1
|
||||
fa064829ca488b4f404889573848bae3
|
||||
134825e765119f4889c848f7ea4801ca
|
||||
48c1f93f48c1fa064829ca488b4f4848
|
||||
89574048ba67bf102b4ae323134889c8
|
||||
48c1f93f48f7ea48c1fa034829ca488b
|
||||
4f504889574848ba5da83909c4859a93
|
||||
4889c848f7ea4801ca48c1f93f48c1fa
|
||||
064829ca488b4f584889575048ba2549
|
||||
9224499224494889c848c1f93f48f7ea
|
||||
48c1fa054829ca488b4f604889575848
|
||||
bae13902455b0d9e234889c848c1f93f
|
||||
48f7ea48c1fa044829ca488b4f684889
|
||||
576048baaf8940ae8940ae894889c848
|
||||
f7ea4801ca48c1f93f48c1fa064829ca
|
||||
488b4f704889576848ba793f729aafd5
|
||||
b3434889c848f7ea48c1f93f48c1fa05
|
||||
4829ca488b4f784889577048ba093485
|
||||
40530834854889c848f7ea4801ca48c1
|
||||
f93f48c1fa064829ca48895778488b8f
|
||||
8000000048bacff753e3a59bc4204889
|
||||
c848c1f93f48f7ea48c1fa044829ca48
|
||||
899780000000c3000000000000000000
|
||||
f30f1efa488b0f488b775848ba53069e
|
||||
6ecd0f8b944889c848f7e24889c84829
|
||||
d048d1e84801c248c1ea06488d04d248
|
||||
bae10217b8c0052e70488d04c04829c1
|
||||
48890f488b4f084889c848f7e24889c8
|
||||
4829d048d1e84801c248c1ea06488d04
|
||||
92488d0442488d04c248ba1768811668
|
||||
8116684829c148894f08488b4f104889
|
||||
c848f7e24889c84829d048d1e84801c2
|
||||
48c1ea06486bd25b4829d148ba175860
|
||||
810516586048894f10488b4f184889c8
|
||||
48f7e24889c84829d048d1e84801c248
|
||||
c1ea06488d14524889d048c1e0054829
|
||||
d048ba31d28e150823ed584829c14889
|
||||
4f18488b4f204889c848f7e24889c848
|
||||
29d048d1e84801c248c1ea06488d0452
|
||||
48c1e0054829d048bad151812fae7ed0
|
||||
514829c148894f20488b4f284889c848
|
||||
f7e24889c84829d048d1e84801c248c1
|
||||
ea06488d045248c1e0054801c24829d1
|
||||
48ba15a8f52b056afd4a48894f28488b
|
||||
4f304889c848f7e24889c84829d048d1
|
||||
e84801c248c1ea06488d04524889c248
|
||||
c1e2054801d048bae5ae9f2d56866f44
|
||||
4829c148894f30488b4f384889c848f7
|
||||
e24889c84829d048d1e84801c248c1ea
|
||||
06488d0492488d0480488d048248bac5
|
||||
27904acecb223e4829c148894f38488b
|
||||
4f404889c848f7e24889c84829d048d1
|
||||
e84801c248c1ea06486bd2674829d148
|
||||
ba6ff60bb1a2343e3248894f40488b4f
|
||||
484889c848f7e24889c84829d048d1e8
|
||||
4801c248c1ea06486bd26b4829d148ba
|
||||
b9507312880b352748894f48488b4f50
|
||||
4889c848f7e24889c84829d048d1e848
|
||||
01c248c1ea06486bd26f4829d14889f2
|
||||
48c1ea0448894f5048b9942449922449
|
||||
92244889d048f7e1488d0cd500000000
|
||||
4829d148ba07cf1128da6af01c48c1e1
|
||||
044829ce488b4f60488977584889c848
|
||||
f7e24889c84829d048d1e84801c248c1
|
||||
ea06486bd2734829d148ba5d13815c13
|
||||
815c1348894f60488b4f684889c848f7
|
||||
e24889c84829d048d1e84801c248c1ea
|
||||
06486bd2774829d148bae3fdc869be56
|
||||
cf0e48894f68488b4f704889c848f7e2
|
||||
4889c84829d048d1e84801c248c1ea06
|
||||
4889d048c1e0044829d0488d04c248ba
|
||||
11680a81a610680a4829c148894f7048
|
||||
8b4f784889c848f7e24889c84829d048
|
||||
d1e84801c248c1ea06486bd27b4829d1
|
||||
48ba77be9f1a2fdd240648894f78488b
|
||||
8f800000004889c848f7e24889c84829
|
||||
d048d1e84801c248c1ea064889d048c1
|
||||
e0054829d0488d04824829c148898f80
|
||||
000000c3000000000000000000000000
|
||||
f30f1efa48ba9581a75bf3c32265488b
|
||||
0f4889c848f7ea4889c848c1f83f48c1
|
||||
fa054829c2488d04d248ba71810b5ce0
|
||||
0217b8488d04c04829c148890f488b4f
|
||||
084889c848f7ea4889c848c1f83f4801
|
||||
ca48c1fa064829c2488d0492488d0442
|
||||
488d04c248ba032dd0022dd0022d4829
|
||||
c148894f08488b4f104889c848f7ea48
|
||||
89c848c1f83f48c1fa044829c2486bd2
|
||||
5b4829d148ba030b2cb0c0020b2c4889
|
||||
4f10488b4f184889c848f7ea4889c848
|
||||
c1f83f48c1fa044829c2488d14524889
|
||||
d048c1e0054829d048ba1969c70a8491
|
||||
76ac4829c148894f18488b4f204889c8
|
||||
48f7ea4889c848c1f83f4801ca48c1fa
|
||||
064829c2488d045248c1e0054829d048
|
||||
bae9a8c017573fe8a84829c148894f20
|
||||
488b4f284889c848f7ea4889c848c1f8
|
||||
3f4801ca48c1fa064829c2488d045248
|
||||
c1e0054801c24829d148ba0bd4fa9502
|
||||
b57ea548894f28488b4f304889c848f7
|
||||
ea4889c848c1f83f4801ca48c1fa0648
|
||||
29c2488d04524889c248c1e2054801d0
|
||||
48ba73d7cf162bc337a24829c148894f
|
||||
30488b4f384889c848f7ea4889c848c1
|
||||
f83f4801ca48c1fa064829c2488d0492
|
||||
488d0480488d048248bae3134825e765
|
||||
119f4829c148894f38488b4f404889c8
|
||||
48f7ea4889c848c1f83f4801ca48c1fa
|
||||
064829c2486bd2674829d148ba67bf10
|
||||
2b4ae3231348894f40488b4f484889c8
|
||||
48f7ea4889c848c1f83f48c1fa034829
|
||||
c2486bd26b4829d148ba5da83909c485
|
||||
9a9348894f48488b4f504889c848f7ea
|
||||
4889c848c1f83f4801ca48c1fa064829
|
||||
c2486bd26f4829d148ba254992244992
|
||||
244948894f50488b4f584889c848f7ea
|
||||
4889c848c1f83f48c1fa054829c2488d
|
||||
04d5000000004829d048bae13902455b
|
||||
0d9e2348c1e0044829c148894f58488b
|
||||
4f604889c848f7ea4889c848c1f83f48
|
||||
c1fa044829c2486bd2734829d148baaf
|
||||
8940ae8940ae8948894f60488b4f6848
|
||||
89c848f7ea4889c848c1f83f4801ca48
|
||||
c1fa064829c2486bd2774829d148ba79
|
||||
3f729aafd5b34348894f68488b4f7048
|
||||
89c848f7ea4889c848c1fa0548c1f83f
|
||||
4829c24889d048c1e0044829d0488d04
|
||||
c248ba09348540530834854829c14889
|
||||
4f70488b4f784889c848f7ea4889c848
|
||||
c1f83f4801ca48c1fa064829c2486bd2
|
||||
7b4829d148bacff753e3a59bc4204889
|
||||
4f78488b8f800000004889c848f7ea48
|
||||
89c848c1f83f48c1fa044829c24889d0
|
||||
48c1e0054829d0488d04824829c14889
|
||||
8f80000000c3
|
||||
</bytechunk>
|
||||
<symbol space="ram" offset="0x100000" name="divoptu"/>
|
||||
<symbol space="ram" offset="0x100280" name="divopti"/>
|
||||
<symbol space="ram" offset="0x100500" name="modoptu"/>
|
||||
<symbol space="ram" offset="0x100880" name="modopti"/>
|
||||
</binaryimage>
|
||||
<script>
|
||||
<com>option integerformat dec</com>
|
||||
<com>parse line extern void divoptu(uint8 *divu);</com>
|
||||
<com>lo fu divoptu</com>
|
||||
<com>decompile</com>
|
||||
<com>print C</com>
|
||||
<com>parse line extern void divopti(int8 *divi);</com>
|
||||
<com>lo fu divopti</com>
|
||||
<com>decompile</com>
|
||||
<com>print C</com>
|
||||
<com>parse line extern void modoptu(uint8 *modu);</com>
|
||||
<com>lo fu modoptu</com>
|
||||
<com>decompile</com>
|
||||
<com>print C</com>
|
||||
<com>parse line extern void modopti(int8 *modi);</com>
|
||||
<com>lo fu modopti</com>
|
||||
<com>decompile</com>
|
||||
<com>print C</com>
|
||||
<com>quit</com>
|
||||
</script>
|
||||
<stringmatch name="Unsigned Division #1" min="1" max="1">\*divu = \*divu / 81;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #2" min="1" max="1">divu\[1\] = divu\[1\] / 89;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #3" min="1" max="1">divu\[2\] = divu\[2\] / 91;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #4" min="1" max="1">divu\[3\] = divu\[3\] / 93;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #5" min="1" max="1">divu\[4\] = divu\[4\] / 95;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #6" min="1" max="1">divu\[5\] = divu\[5\] / 97;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #7" min="1" max="1">divu\[6\] = divu\[6\] / 99;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #8" min="1" max="1">divu\[7\] = divu\[7\] / 101;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #9" min="1" max="1">divu\[8\] = divu\[8\] / 103;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #10" min="1" max="1">divu\[9\] = divu\[9\] / 107;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #11" min="1" max="1">divu\[10\] = divu\[10\] / 111;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #12" min="1" max="1">divu\[11\] = divu\[11\] / 112;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #13" min="1" max="1">divu\[12\] = divu\[12\] / 115;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #14" min="1" max="1">divu\[13\] = divu\[13\] / 119;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #15" min="1" max="1">divu\[14\] = divu\[14\] / 121;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #16" min="1" max="1">divu\[15\] = divu\[15\] / 123;</stringmatch>
|
||||
<stringmatch name="Unsigned Division #17" min="1" max="1">divu\[16\] = divu\[16\] / 125;</stringmatch>
|
||||
<stringmatch name="Signed Division #1" min="1" max="1">\*divi = \*divi / 81;</stringmatch>
|
||||
<stringmatch name="Signed Division #2" min="1" max="1">divi\[1\] = divi\[1\] / 89;</stringmatch>
|
||||
<stringmatch name="Signed Division #3" min="1" max="1">divi\[2\] = divi\[2\] / 91;</stringmatch>
|
||||
<stringmatch name="Signed Division #4" min="1" max="1">divi\[3\] = divi\[3\] / 93;</stringmatch>
|
||||
<stringmatch name="Signed Division #5" min="1" max="1">divi\[4\] = divi\[4\] / 95;</stringmatch>
|
||||
<stringmatch name="Signed Division #6" min="1" max="1">divi\[5\] = divi\[5\] / 97;</stringmatch>
|
||||
<stringmatch name="Signed Division #7" min="1" max="1">divi\[6\] = divi\[6\] / 99;</stringmatch>
|
||||
<stringmatch name="Signed Division #8" min="1" max="1">divi\[7\] = divi\[7\] / 101;</stringmatch>
|
||||
<stringmatch name="Signed Division #9" min="1" max="1">divi\[8\] = divi\[8\] / 103;</stringmatch>
|
||||
<stringmatch name="Signed Division #10" min="1" max="1">divi\[9\] = divi\[9\] / 107;</stringmatch>
|
||||
<stringmatch name="Signed Division #11" min="1" max="1">divi\[10\] = divi\[10\] / 111;</stringmatch>
|
||||
<stringmatch name="Signed Division #12" min="1" max="1">divi\[11\] = divi\[11\] / 112;</stringmatch>
|
||||
<stringmatch name="Signed Division #13" min="1" max="1">divi\[12\] = divi\[12\] / 115;</stringmatch>
|
||||
<stringmatch name="Signed Division #14" min="1" max="1">divi\[13\] = divi\[13\] / 119;</stringmatch>
|
||||
<stringmatch name="Signed Division #15" min="1" max="1">divi\[14\] = divi\[14\] / 121;</stringmatch>
|
||||
<stringmatch name="Signed Division #16" min="1" max="1">divi\[15\] = divi\[15\] / 123;</stringmatch>
|
||||
<stringmatch name="Signed Division #17" min="1" max="1">divi\[16\] = divi\[16\] / 125;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #1" min="1" max="1">\*modu = \*modu % 81;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #2" min="1" max="1">modu\[1\] = modu\[1\] % 89;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #3" min="1" max="1">modu\[2\] = modu\[2\] % 91;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #4" min="1" max="1">modu\[3\] = modu\[3\] % 93;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #5" min="1" max="1">modu\[4\] = modu\[4\] % 95;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #6" min="1" max="1">modu\[5\] = modu\[5\] % 97;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #7" min="1" max="1">modu\[6\] = modu\[6\] % 99;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #8" min="1" max="1">modu\[7\] = modu\[7\] % 101;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #9" min="1" max="1">modu\[8\] = modu\[8\] % 103;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #10" min="1" max="1">modu\[9\] = modu\[9\] % 107;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #11" min="1" max="1">modu\[10\] = modu\[10\] % 111;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #12" min="1" max="1">modu\[11\] = modu\[11\] % 112;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #13" min="1" max="1">modu\[12\] = modu\[12\] % 115;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #14" min="1" max="1">modu\[13\] = modu\[13\] % 119;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #15" min="1" max="1">modu\[14\] = modu\[14\] % 121;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #16" min="1" max="1">modu\[15\] = modu\[15\] % 123;</stringmatch>
|
||||
<stringmatch name="Unsigned Modulo #17" min="1" max="1">modu\[16\] = modu\[16\] % 125;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #1" min="1" max="1">\*modi = \*modi % 81;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #2" min="1" max="1">modi\[1\] = modi\[1\] % 89;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #3" min="1" max="1">modi\[2\] = modi\[2\] % 91;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #4" min="1" max="1">modi\[3\] = modi\[3\] % 93;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #5" min="1" max="1">modi\[4\] = modi\[4\] % 95;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #6" min="1" max="1">modi\[5\] = modi\[5\] % 97;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #7" min="1" max="1">modi\[6\] = modi\[6\] % 99;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #8" min="1" max="1">modi\[7\] = modi\[7\] % 101;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #9" min="1" max="1">modi\[8\] = modi\[8\] % 103;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #10" min="1" max="1">modi\[9\] = modi\[9\] % 107;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #11" min="1" max="1">modi\[10\] = modi\[10\] % 111;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #12" min="1" max="1">modi\[11\] = modi\[11\] % 112;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #13" min="1" max="1">modi\[12\] = modi\[12\] % 115;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #14" min="1" max="1">modi\[13\] = modi\[13\] % 119;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #15" min="1" max="1">modi\[14\] = modi\[14\] % 121;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #16" min="1" max="1">modi\[15\] = modi\[15\] % 123;</stringmatch>
|
||||
<stringmatch name="Signed Modulo #17" min="1" max="1">modi\[16\] = modi\[16\] % 125;</stringmatch>
|
||||
</decompilertest>
|
Loading…
Reference in New Issue
Block a user